From 6a7392058e69956d610acefa7e3ce1cd60c8f5a6 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 17 May 2022 13:08:56 +0200 Subject: [PATCH] Complete documentation for 3.11.0 (#3464) * :busts_in_silhouette: update contributor and sponsor list * :construction: document BJData format * :construction: document BJData format * :memo: clarified documentation of [json.exception.parse_error.112] * :pencil2: adjust titles * :memo: add more examples * :rotating_light: adjust warnings for index.md files * :memo: add more examples * :fire: remove example for deprecated code * :memo: add missing enum entry * :memo: overwork table for binary formats * :white_check_mark: add test to create table for binary formats * :memo: fix wording in example * :memo: add more examples * Update iterators.md (#3481) * :sparkles: add check for overloads to linter #3455 * :busts_in_silhouette: update contributor list * :memo: add more examples * :memo: fix documentation * :memo: add more examples * :art: fix indentation * :fire: remove example for destructor * :memo: overwork documentation * Updated BJData documentation, #3464 (#3493) * update bjdata.md for #3464 * Minor edit * Fix URL typo * Add info on demoting ND array to a 1-D optimized array when singleton dimension Co-authored-by: Chaoqi Zhang Co-authored-by: Qianqian Fang --- README.md | 22 +- ...h_subtype__byte_container_with_subtype.cpp | 23 ++ ...ubtype__byte_container_with_subtype.output | 3 + ..._container_with_subtype__clear_subtype.cpp | 21 ++ ...ntainer_with_subtype__clear_subtype.output | 2 + ...te_container_with_subtype__has_subtype.cpp | 19 ++ ...container_with_subtype__has_subtype.output | 2 + ...te_container_with_subtype__set_subtype.cpp | 22 ++ ...container_with_subtype__set_subtype.output | 2 + .../byte_container_with_subtype__subtype.cpp | 22 ++ ...yte_container_with_subtype__subtype.output | 2 + docs/examples/cbor_tag_handler_t.cpp | 28 +++ docs/examples/cbor_tag_handler_t.output | 3 + docs/examples/default_object_comparator_t.cpp | 11 + .../default_object_comparator_t.output | 2 + docs/examples/error_handler_t.cpp | 24 ++ docs/examples/error_handler_t.output | 3 + docs/examples/from_bjdata.cpp | 20 ++ docs/examples/from_bjdata.output | 4 + docs/examples/get_allocator.cpp | 18 ++ docs/examples/get_allocator.output | 1 + docs/examples/iterator_wrapper.cpp | 29 --- docs/examples/iterator_wrapper.output | 7 - .../json_pointer__operator_string.cpp | 19 ++ .../json_pointer__operator_string.output | 2 + docs/examples/json_pointer__string_t.cpp | 13 + docs/examples/json_pointer__string_t.output | 2 + docs/examples/json_pointer__to_string.cpp | 1 - docs/examples/nlohmann_json_version.cpp | 12 + docs/examples/nlohmann_json_version.output | 1 + docs/examples/object_comparator_t.cpp | 11 + docs/examples/object_comparator_t.output | 2 + docs/examples/ordered_json.cpp | 14 ++ docs/examples/ordered_json.output | 5 + docs/examples/sax_parse.cpp | 37 +-- docs/examples/sax_parse.output | 39 ++- docs/examples/sax_parse__binary.cpp | 114 +++++++++ docs/examples/sax_parse__binary.output | 3 + docs/examples/to_bjdata.cpp | 63 +++++ docs/examples/to_bjdata.output | 4 + docs/mkdocs/docs/api/basic_json/at.md | 1 + docs/mkdocs/docs/api/basic_json/basic_json.md | 2 +- .../docs/api/basic_json/cbor_tag_handler_t.md | 17 ++ docs/mkdocs/docs/api/basic_json/contains.md | 4 +- .../basic_json/default_object_comparator_t.md | 16 ++ .../docs/api/basic_json/error_handler_t.md | 17 ++ .../mkdocs/docs/api/basic_json/from_bjdata.md | 93 +++++++ .../docs/api/basic_json/get_allocator.md | 22 +- docs/mkdocs/docs/api/basic_json/index.md | 2 + .../docs/api/basic_json/input_format_t.md | 22 +- .../api/basic_json/object_comparator_t.md | 17 +- docs/mkdocs/docs/api/basic_json/operator+=.md | 9 +- docs/mkdocs/docs/api/basic_json/operator[].md | 2 + .../docs/api/basic_json/operator_ValueType.md | 1 - .../mkdocs/docs/api/basic_json/operator_eq.md | 4 +- docs/mkdocs/docs/api/basic_json/push_back.md | 9 +- docs/mkdocs/docs/api/basic_json/to_bjdata.md | 70 ++++++ docs/mkdocs/docs/api/basic_json/value_t.md | 16 ++ .../byte_container_with_subtype.md | 16 ++ .../clear_subtype.md | 16 ++ .../has_subtype.md | 16 ++ .../set_subtype.md | 16 ++ .../byte_container_with_subtype/subtype.md | 17 ++ docs/mkdocs/docs/api/json.md | 16 ++ docs/mkdocs/docs/api/json_pointer/index.md | 8 +- .../docs/api/json_pointer/operator_string.md | 16 ++ docs/mkdocs/docs/api/json_pointer/string_t.md | 16 ++ docs/mkdocs/docs/api/json_sax/binary.md | 16 ++ docs/mkdocs/docs/api/json_sax/boolean.md | 16 ++ docs/mkdocs/docs/api/json_sax/end_array.md | 16 ++ docs/mkdocs/docs/api/json_sax/end_object.md | 16 ++ docs/mkdocs/docs/api/json_sax/key.md | 16 ++ docs/mkdocs/docs/api/json_sax/null.md | 16 ++ docs/mkdocs/docs/api/json_sax/number_float.md | 16 ++ .../docs/api/json_sax/number_integer.md | 16 ++ .../docs/api/json_sax/number_unsigned.md | 16 ++ docs/mkdocs/docs/api/json_sax/parse_error.md | 16 ++ docs/mkdocs/docs/api/json_sax/start_array.md | 16 ++ docs/mkdocs/docs/api/json_sax/start_object.md | 16 ++ docs/mkdocs/docs/api/json_sax/string.md | 16 ++ .../mkdocs/docs/api/macros/json_has_cpp_11.md | 13 + .../docs/api/macros/json_has_filesystem.md | 13 + docs/mkdocs/docs/api/macros/json_no_io.md | 14 ++ .../docs/api/macros/json_noexception.md | 13 + .../json_skip_unsupported_compiler_check.md | 13 + .../api/macros/nlohmann_json_version_major.md | 17 ++ docs/mkdocs/docs/api/ordered_json.md | 17 ++ .../docs/features/binary_formats/bjdata.md | 209 ++++++++++++++++ .../docs/features/binary_formats/index.md | 21 +- docs/mkdocs/docs/features/binary_values.md | 100 +++++++- .../features/element_access/checked_access.md | 44 ++-- .../element_access/unchecked_access.md | 43 ++-- docs/mkdocs/docs/features/iterators.md | 2 +- docs/mkdocs/docs/features/object_order.md | 21 +- docs/mkdocs/docs/home/exceptions.md | 39 ++- docs/mkdocs/mkdocs.yml | 3 + docs/mkdocs/scripts/check_structure.py | 59 +++-- include/nlohmann/json.hpp | 23 -- single_include/nlohmann/json.hpp | 23 -- tests/CMakeLists.txt | 2 +- tests/src/unit-binary_formats.cpp | 232 ++++++++++++++++++ tests/src/unit-bjdata.cpp | 15 -- 102 files changed, 1990 insertions(+), 247 deletions(-) create mode 100644 docs/examples/byte_container_with_subtype__byte_container_with_subtype.cpp create mode 100644 docs/examples/byte_container_with_subtype__byte_container_with_subtype.output create mode 100644 docs/examples/byte_container_with_subtype__clear_subtype.cpp create mode 100644 docs/examples/byte_container_with_subtype__clear_subtype.output create mode 100644 docs/examples/byte_container_with_subtype__has_subtype.cpp create mode 100644 docs/examples/byte_container_with_subtype__has_subtype.output create mode 100644 docs/examples/byte_container_with_subtype__set_subtype.cpp create mode 100644 docs/examples/byte_container_with_subtype__set_subtype.output create mode 100644 docs/examples/byte_container_with_subtype__subtype.cpp create mode 100644 docs/examples/byte_container_with_subtype__subtype.output create mode 100644 docs/examples/cbor_tag_handler_t.cpp create mode 100644 docs/examples/cbor_tag_handler_t.output create mode 100644 docs/examples/default_object_comparator_t.cpp create mode 100644 docs/examples/default_object_comparator_t.output create mode 100644 docs/examples/error_handler_t.cpp create mode 100644 docs/examples/error_handler_t.output create mode 100644 docs/examples/from_bjdata.cpp create mode 100644 docs/examples/from_bjdata.output create mode 100644 docs/examples/get_allocator.cpp create mode 100644 docs/examples/get_allocator.output delete mode 100644 docs/examples/iterator_wrapper.cpp delete mode 100644 docs/examples/iterator_wrapper.output create mode 100644 docs/examples/json_pointer__operator_string.cpp create mode 100644 docs/examples/json_pointer__operator_string.output create mode 100644 docs/examples/json_pointer__string_t.cpp create mode 100644 docs/examples/json_pointer__string_t.output create mode 100644 docs/examples/nlohmann_json_version.cpp create mode 100644 docs/examples/nlohmann_json_version.output create mode 100644 docs/examples/object_comparator_t.cpp create mode 100644 docs/examples/object_comparator_t.output create mode 100644 docs/examples/ordered_json.cpp create mode 100644 docs/examples/ordered_json.output create mode 100644 docs/examples/sax_parse__binary.cpp create mode 100644 docs/examples/sax_parse__binary.output create mode 100644 docs/examples/to_bjdata.cpp create mode 100644 docs/examples/to_bjdata.output create mode 100644 docs/mkdocs/docs/api/basic_json/from_bjdata.md create mode 100644 docs/mkdocs/docs/api/basic_json/to_bjdata.md create mode 100644 docs/mkdocs/docs/features/binary_formats/bjdata.md create mode 100644 tests/src/unit-binary_formats.cpp diff --git a/README.md b/README.md index 3f61377ba..96beb8899 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ There are myriads of [JSON](https://json.org) libraries out there, and each may - **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. -- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](https://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). +- **Serious testing**. Our code is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](https://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). Other aspects were not so important to us: @@ -69,6 +69,10 @@ See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/. You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nlohmann). +### :office: Corporate Sponsor + +[![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Codacy-logo-black.svg/320px-Codacy-logo-black.svg.png)](https://github.com/codacy) + ### :label: Named Sponsors - [Michael Hartmann](https://github.com/reFX-Mike) @@ -1599,6 +1603,20 @@ I deeply appreciate the help of the following people. - [Dirk Stolle](https://github.com/striezel) fixed typos in documentation. - [Daniel Albuschat](https://github.com/daniel-kun) corrected the parameter name in the `parse` documentation. - [Prince Mendiratta](https://github.com/Prince-Mendiratta) fixed a link to the FAQ. +- [Florian Albrechtskirchinger](https://github.com/falbrechtskirchinger) implemented `std::string_view` support for object keys and made dozens of other improvements. +- [Qianqian Fang](https://github.com/fangq) implemented the Binary JData (BJData) format. +- [pketelsen](https://github.com/pketelsen) added macros `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` and `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`. +- [DarkZeros](https://github.com/DarkZeros) adjusted to code to not clash with Arduino defines. +- [flagarde](https://github.com/flagarde) fixed the output of `meta()` for MSVC. +- [Giovanni Cerretani](https://github.com/gcerretani) fixed a check for `std::filesystem`. +- [Dimitris Apostolou](https://github.com/rex4539) fixed a typo. +- [Ferry Huberts](https://github.com/fhuberts) fixed a typo. +- [Michael Nosthoff](https://github.com/heinemml) fixed a typo. +- [JungHoon Lee](https://github.com/jhnlee) fixed a typo. +- [Faruk D.](https://github.com/fdiblen) fixed the CITATION.CFF file. +- [Andrea Cocito](https://github.com/puffetto) added a clarification on macro usage to the documentation. +- [Krzysiek Karbowiak](https://github.com/kkarbowiak) refactored the tests to use `CHECK_THROWS_WITH_AS`. +- [Chaoqi Zhang](https://github.com/prncoprs) fixed a typo. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. @@ -1613,7 +1631,7 @@ The library itself consists of a single header file licensed under the MIT licen - [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation - [**Clang**](https://clang.llvm.org) for compilation with code sanitizers - [**CMake**](https://cmake.org) for build automation -- [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json) +- [**Codacy**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json) - [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json) - [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json) - [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis diff --git a/docs/examples/byte_container_with_subtype__byte_container_with_subtype.cpp b/docs/examples/byte_container_with_subtype__byte_container_with_subtype.cpp new file mode 100644 index 000000000..1c10be5c2 --- /dev/null +++ b/docs/examples/byte_container_with_subtype__byte_container_with_subtype.cpp @@ -0,0 +1,23 @@ +#include +#include + +// define a byte container based on std::vector +using byte_container_with_subtype = nlohmann::byte_container_with_subtype>; + +using json = nlohmann::json; + +int main() +{ + // (1) create empty container + auto c1 = byte_container_with_subtype(); + + std::vector bytes = {{0xca, 0xfe, 0xba, 0xbe}}; + + // (2) create container + auto c2 = byte_container_with_subtype(bytes); + + // (3) create container with subtype + auto c3 = byte_container_with_subtype(bytes, 42); + + std::cout << json(c1) << "\n" << json(c2) << "\n" << json(c3) << std::endl; +} diff --git a/docs/examples/byte_container_with_subtype__byte_container_with_subtype.output b/docs/examples/byte_container_with_subtype__byte_container_with_subtype.output new file mode 100644 index 000000000..67ac1b2ef --- /dev/null +++ b/docs/examples/byte_container_with_subtype__byte_container_with_subtype.output @@ -0,0 +1,3 @@ +{"bytes":[],"subtype":null} +{"bytes":[202,254,186,190],"subtype":null} +{"bytes":[202,254,186,190],"subtype":42} diff --git a/docs/examples/byte_container_with_subtype__clear_subtype.cpp b/docs/examples/byte_container_with_subtype__clear_subtype.cpp new file mode 100644 index 000000000..f9ce6842b --- /dev/null +++ b/docs/examples/byte_container_with_subtype__clear_subtype.cpp @@ -0,0 +1,21 @@ +#include +#include + +// define a byte container based on std::vector +using byte_container_with_subtype = nlohmann::byte_container_with_subtype>; + +using json = nlohmann::json; + +int main() +{ + std::vector bytes = {{0xca, 0xfe, 0xba, 0xbe}}; + + // create container with subtype + auto c1 = byte_container_with_subtype(bytes, 42); + + std::cout << "before calling clear_subtype(): " << json(c1) << '\n'; + + c1.clear_subtype(); + + std::cout << "after calling clear_subtype(): " << json(c1) << '\n'; +} diff --git a/docs/examples/byte_container_with_subtype__clear_subtype.output b/docs/examples/byte_container_with_subtype__clear_subtype.output new file mode 100644 index 000000000..9d8212946 --- /dev/null +++ b/docs/examples/byte_container_with_subtype__clear_subtype.output @@ -0,0 +1,2 @@ +before calling clear_subtype(): {"bytes":[202,254,186,190],"subtype":42} +after calling clear_subtype(): {"bytes":[202,254,186,190],"subtype":null} diff --git a/docs/examples/byte_container_with_subtype__has_subtype.cpp b/docs/examples/byte_container_with_subtype__has_subtype.cpp new file mode 100644 index 000000000..61c21eaae --- /dev/null +++ b/docs/examples/byte_container_with_subtype__has_subtype.cpp @@ -0,0 +1,19 @@ +#include +#include + +// define a byte container based on std::vector +using byte_container_with_subtype = nlohmann::byte_container_with_subtype>; + +int main() +{ + std::vector bytes = {{0xca, 0xfe, 0xba, 0xbe}}; + + // create container + auto c1 = byte_container_with_subtype(bytes); + + // create container with subtype + auto c2 = byte_container_with_subtype(bytes, 42); + + std::cout << std::boolalpha << "c1.has_subtype() = " << c1.has_subtype() + << "\nc2.has_subtype() = " << c2.has_subtype() << std::endl; +} diff --git a/docs/examples/byte_container_with_subtype__has_subtype.output b/docs/examples/byte_container_with_subtype__has_subtype.output new file mode 100644 index 000000000..f4aade2a1 --- /dev/null +++ b/docs/examples/byte_container_with_subtype__has_subtype.output @@ -0,0 +1,2 @@ +c1.has_subtype() = false +c2.has_subtype() = true diff --git a/docs/examples/byte_container_with_subtype__set_subtype.cpp b/docs/examples/byte_container_with_subtype__set_subtype.cpp new file mode 100644 index 000000000..b2694c54d --- /dev/null +++ b/docs/examples/byte_container_with_subtype__set_subtype.cpp @@ -0,0 +1,22 @@ +#include +#include + +// define a byte container based on std::vector +using byte_container_with_subtype = nlohmann::byte_container_with_subtype>; + +using json = nlohmann::json; + +int main() +{ + std::vector bytes = {{0xca, 0xfe, 0xba, 0xbe}}; + + // create container without subtype + auto c = byte_container_with_subtype(bytes); + + std::cout << "before calling set_subtype(42): " << json(c) << '\n'; + + // set the subtype + c.set_subtype(42); + + std::cout << "after calling set_subtype(42): " << json(c) << '\n'; +} diff --git a/docs/examples/byte_container_with_subtype__set_subtype.output b/docs/examples/byte_container_with_subtype__set_subtype.output new file mode 100644 index 000000000..648b3ef24 --- /dev/null +++ b/docs/examples/byte_container_with_subtype__set_subtype.output @@ -0,0 +1,2 @@ +before calling set_subtype(42): {"bytes":[202,254,186,190],"subtype":null} +after calling set_subtype(42): {"bytes":[202,254,186,190],"subtype":42} diff --git a/docs/examples/byte_container_with_subtype__subtype.cpp b/docs/examples/byte_container_with_subtype__subtype.cpp new file mode 100644 index 000000000..cd230ade1 --- /dev/null +++ b/docs/examples/byte_container_with_subtype__subtype.cpp @@ -0,0 +1,22 @@ +#include +#include + +// define a byte container based on std::vector +using byte_container_with_subtype = nlohmann::byte_container_with_subtype>; + +int main() +{ + std::vector bytes = {{0xca, 0xfe, 0xba, 0xbe}}; + + // create container + auto c1 = byte_container_with_subtype(bytes); + + // create container with subtype + auto c2 = byte_container_with_subtype(bytes, 42); + + std::cout << "c1.subtype() = " << c1.subtype() + << "\nc2.subtype() = " << c2.subtype() << std::endl; + + // in case no subtype is set, return special value + assert(c1.subtype() == static_cast(-1)); +} diff --git a/docs/examples/byte_container_with_subtype__subtype.output b/docs/examples/byte_container_with_subtype__subtype.output new file mode 100644 index 000000000..47955277b --- /dev/null +++ b/docs/examples/byte_container_with_subtype__subtype.output @@ -0,0 +1,2 @@ +c1.subtype() = 18446744073709551615 +c2.subtype() = 42 diff --git a/docs/examples/cbor_tag_handler_t.cpp b/docs/examples/cbor_tag_handler_t.cpp new file mode 100644 index 000000000..79052c7a0 --- /dev/null +++ b/docs/examples/cbor_tag_handler_t.cpp @@ -0,0 +1,28 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // tagged byte string + std::vector vec = {{0xd8, 0x42, 0x44, 0xcA, 0xfe, 0xba, 0xbe}}; + + // cbor_tag_handler_t::error throws + try + { + auto b_throw_on_tag = json::from_cbor(vec, true, true, json::cbor_tag_handler_t::error); + } + catch (json::parse_error& e) + { + std::cout << e.what() << std::endl; + } + + // cbor_tag_handler_t::ignore ignores the tag + auto b_ignore_tag = json::from_cbor(vec, true, true, json::cbor_tag_handler_t::ignore); + std::cout << b_ignore_tag << std::endl; + + // cbor_tag_handler_t::store stores the tag as binary subtype + auto b_store_tag = json::from_cbor(vec, true, true, json::cbor_tag_handler_t::store); + std::cout << b_store_tag << std::endl; +} diff --git a/docs/examples/cbor_tag_handler_t.output b/docs/examples/cbor_tag_handler_t.output new file mode 100644 index 000000000..18920b137 --- /dev/null +++ b/docs/examples/cbor_tag_handler_t.output @@ -0,0 +1,3 @@ +[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing CBOR value: invalid byte: 0xD8 +{"bytes":[202,254,186,190],"subtype":null} +{"bytes":[202,254,186,190],"subtype":66} diff --git a/docs/examples/default_object_comparator_t.cpp b/docs/examples/default_object_comparator_t.cpp new file mode 100644 index 000000000..9f200fe6b --- /dev/null +++ b/docs/examples/default_object_comparator_t.cpp @@ -0,0 +1,11 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::boolalpha + << "one < two : " << json::default_object_comparator_t{}("one", "two") << "\n" + << "three < four : " << json::default_object_comparator_t{}("three", "four") << std::endl; +} diff --git a/docs/examples/default_object_comparator_t.output b/docs/examples/default_object_comparator_t.output new file mode 100644 index 000000000..b1daf3b96 --- /dev/null +++ b/docs/examples/default_object_comparator_t.output @@ -0,0 +1,2 @@ +one < two : true +three < four : false diff --git a/docs/examples/error_handler_t.cpp b/docs/examples/error_handler_t.cpp new file mode 100644 index 000000000..add3f3b2d --- /dev/null +++ b/docs/examples/error_handler_t.cpp @@ -0,0 +1,24 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create JSON value with invalid UTF-8 byte sequence + json j_invalid = "ä\xA9ü"; + try + { + std::cout << j_invalid.dump() << std::endl; + } + catch (json::type_error& e) + { + std::cout << e.what() << std::endl; + } + + std::cout << "string with replaced invalid characters: " + << j_invalid.dump(-1, ' ', false, json::error_handler_t::replace) + << "\nstring with ignored invalid characters: " + << j_invalid.dump(-1, ' ', false, json::error_handler_t::ignore) + << '\n'; +} diff --git a/docs/examples/error_handler_t.output b/docs/examples/error_handler_t.output new file mode 100644 index 000000000..718d62bee --- /dev/null +++ b/docs/examples/error_handler_t.output @@ -0,0 +1,3 @@ +[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9 +string with replaced invalid characters: "ä�ü" +string with ignored invalid characters: "äü" diff --git a/docs/examples/from_bjdata.cpp b/docs/examples/from_bjdata.cpp new file mode 100644 index 000000000..961164c29 --- /dev/null +++ b/docs/examples/from_bjdata.cpp @@ -0,0 +1,20 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create byte vector + std::vector v = {0x7B, 0x69, 0x07, 0x63, 0x6F, 0x6D, 0x70, 0x61, + 0x63, 0x74, 0x54, 0x69, 0x06, 0x73, 0x63, 0x68, + 0x65, 0x6D, 0x61, 0x69, 0x00, 0x7D + }; + + // deserialize it with BJData + json j = json::from_bjdata(v); + + // print the deserialized JSON value + std::cout << std::setw(2) << j << std::endl; +} diff --git a/docs/examples/from_bjdata.output b/docs/examples/from_bjdata.output new file mode 100644 index 000000000..259f63bd4 --- /dev/null +++ b/docs/examples/from_bjdata.output @@ -0,0 +1,4 @@ +{ + "compact": true, + "schema": 0 +} diff --git a/docs/examples/get_allocator.cpp b/docs/examples/get_allocator.cpp new file mode 100644 index 000000000..35079a10c --- /dev/null +++ b/docs/examples/get_allocator.cpp @@ -0,0 +1,18 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + auto alloc = json::get_allocator(); + using traits_t = std::allocator_traits; + + json* j = traits_t::allocate(alloc, 1); + traits_t::construct(alloc, j, "Hello, world!"); + + std::cout << *j << std::endl; + + traits_t::destroy(alloc, j); + traits_t::deallocate(alloc, j, 1); +} diff --git a/docs/examples/get_allocator.output b/docs/examples/get_allocator.output new file mode 100644 index 000000000..8effb3e8c --- /dev/null +++ b/docs/examples/get_allocator.output @@ -0,0 +1 @@ +"Hello, world!" diff --git a/docs/examples/iterator_wrapper.cpp b/docs/examples/iterator_wrapper.cpp deleted file mode 100644 index 84d37254b..000000000 --- a/docs/examples/iterator_wrapper.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include - -using json = nlohmann::json; - -int main() -{ - // create JSON values - json j_object = {{"one", 1}, {"two", 2}}; - json j_array = {1, 2, 4, 8, 16}; - - ////////////////////////////////////////////////////////////////////////// - // The static function iterator_wrapper was deprecated in version 3.1.0 - // and will be removed in version 4.0.0. Please replace all occurrences - // of iterator_wrapper(j) with j.items(). - ////////////////////////////////////////////////////////////////////////// - - // example for an object - for (auto& x : json::iterator_wrapper(j_object)) - { - std::cout << "key: " << x.key() << ", value: " << x.value() << '\n'; - } - - // example for an array - for (auto& x : json::iterator_wrapper(j_array)) - { - std::cout << "key: " << x.key() << ", value: " << x.value() << '\n'; - } -} diff --git a/docs/examples/iterator_wrapper.output b/docs/examples/iterator_wrapper.output deleted file mode 100644 index 89b09f524..000000000 --- a/docs/examples/iterator_wrapper.output +++ /dev/null @@ -1,7 +0,0 @@ -key: one, value: 1 -key: two, value: 2 -key: 0, value: 1 -key: 1, value: 2 -key: 2, value: 4 -key: 3, value: 8 -key: 4, value: 16 diff --git a/docs/examples/json_pointer__operator_string.cpp b/docs/examples/json_pointer__operator_string.cpp new file mode 100644 index 000000000..56f213020 --- /dev/null +++ b/docs/examples/json_pointer__operator_string.cpp @@ -0,0 +1,19 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // different JSON Pointers + json::json_pointer ptr1("/foo/0"); + json::json_pointer ptr2("/a~1b"); + + // implicit conversion to string + std::string s; + s += ptr1; + s += "\n"; + s += ptr2; + + std::cout << s << std::endl; +} diff --git a/docs/examples/json_pointer__operator_string.output b/docs/examples/json_pointer__operator_string.output new file mode 100644 index 000000000..ec6aba2c2 --- /dev/null +++ b/docs/examples/json_pointer__operator_string.output @@ -0,0 +1,2 @@ +/foo/0 +/a~1b diff --git a/docs/examples/json_pointer__string_t.cpp b/docs/examples/json_pointer__string_t.cpp new file mode 100644 index 000000000..fbe0f179e --- /dev/null +++ b/docs/examples/json_pointer__string_t.cpp @@ -0,0 +1,13 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + json::json_pointer::string_t s = "This is a string."; + + std::cout << s << std::endl; + + std::cout << std::boolalpha << std::is_same::value << std::endl; +} diff --git a/docs/examples/json_pointer__string_t.output b/docs/examples/json_pointer__string_t.output new file mode 100644 index 000000000..d87113724 --- /dev/null +++ b/docs/examples/json_pointer__string_t.output @@ -0,0 +1,2 @@ +This is a string. +true diff --git a/docs/examples/json_pointer__to_string.cpp b/docs/examples/json_pointer__to_string.cpp index da397cdf4..ae1361aaa 100644 --- a/docs/examples/json_pointer__to_string.cpp +++ b/docs/examples/json_pointer__to_string.cpp @@ -19,7 +19,6 @@ int main() json::json_pointer ptr11("/ "); json::json_pointer ptr12("/m~0n"); - std::cout << ptr1.to_string() << '\n' << ptr2.to_string() << '\n' << ptr3.to_string() << '\n' diff --git a/docs/examples/nlohmann_json_version.cpp b/docs/examples/nlohmann_json_version.cpp new file mode 100644 index 000000000..ca5f53728 --- /dev/null +++ b/docs/examples/nlohmann_json_version.cpp @@ -0,0 +1,12 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << "JSON for Modern C++ version " + << NLOHMANN_JSON_VERSION_MAJOR << "." + << NLOHMANN_JSON_VERSION_MINOR << "." + << NLOHMANN_JSON_VERSION_PATCH << std::endl; +} diff --git a/docs/examples/nlohmann_json_version.output b/docs/examples/nlohmann_json_version.output new file mode 100644 index 000000000..600343999 --- /dev/null +++ b/docs/examples/nlohmann_json_version.output @@ -0,0 +1 @@ +JSON for Modern C++ version 3.10.5 diff --git a/docs/examples/object_comparator_t.cpp b/docs/examples/object_comparator_t.cpp new file mode 100644 index 000000000..6b82c7ca6 --- /dev/null +++ b/docs/examples/object_comparator_t.cpp @@ -0,0 +1,11 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + std::cout << std::boolalpha + << "json::object_comparator_t(\"one\", \"two\") = " << json::object_comparator_t{}("one", "two") << "\n" + << "json::object_comparator_t(\"three\", \"four\") = " << json::object_comparator_t{}("three", "four") << std::endl; +} diff --git a/docs/examples/object_comparator_t.output b/docs/examples/object_comparator_t.output new file mode 100644 index 000000000..63620edb4 --- /dev/null +++ b/docs/examples/object_comparator_t.output @@ -0,0 +1,2 @@ +json::object_comparator_t("one", "two") = true +json::object_comparator_t("three", "four") = false diff --git a/docs/examples/ordered_json.cpp b/docs/examples/ordered_json.cpp new file mode 100644 index 000000000..effad530c --- /dev/null +++ b/docs/examples/ordered_json.cpp @@ -0,0 +1,14 @@ +#include +#include + +using ordered_json = nlohmann::ordered_json; + +int main() +{ + ordered_json j; + j["one"] = 1; + j["two"] = 2; + j["three"] = 3; + + std::cout << j.dump(2) << '\n'; +} diff --git a/docs/examples/ordered_json.output b/docs/examples/ordered_json.output new file mode 100644 index 000000000..120cbb284 --- /dev/null +++ b/docs/examples/ordered_json.output @@ -0,0 +1,5 @@ +{ + "one": 1, + "two": 2, + "three": 3 +} diff --git a/docs/examples/sax_parse.cpp b/docs/examples/sax_parse.cpp index 45273eb6c..8602687e3 100644 --- a/docs/examples/sax_parse.cpp +++ b/docs/examples/sax_parse.cpp @@ -6,7 +6,7 @@ using json = nlohmann::json; // a simple event consumer that collects string representations of the passed -// values; not inheriting from json::json_sax_t is not required, but can +// values; note inheriting from json::json_sax_t is not required, but can // help not to forget a required function class sax_event_consumer : public json::json_sax_t { @@ -15,79 +15,79 @@ class sax_event_consumer : public json::json_sax_t bool null() override { - events.push_back("value: null"); + events.push_back("null()"); return true; } bool boolean(bool val) override { - events.push_back("value: " + std::string(val ? "true" : "false")); + events.push_back("boolean(val=" + std::string(val ? "true" : "false") + ")"); return true; } bool number_integer(number_integer_t val) override { - events.push_back("value: " + std::to_string(val)); + events.push_back("number_integer(val=" + std::to_string(val) + ")"); return true; } bool number_unsigned(number_unsigned_t val) override { - events.push_back("value: " + std::to_string(val)); + events.push_back("number_unsigned(val=" + std::to_string(val) + ")"); return true; } bool number_float(number_float_t val, const string_t& s) override { - events.push_back("value: " + s); + events.push_back("number_float(val=" + std::to_string(val) + ", s=" + s + ")"); return true; } bool string(string_t& val) override { - events.push_back("value: " + val); + events.push_back("string(val=" + val + ")"); return true; } bool start_object(std::size_t elements) override { - events.push_back("start: object"); + events.push_back("start_object(elements=" + std::to_string(elements) + ")"); return true; } bool end_object() override { - events.push_back("end: object"); + events.push_back("end_object()"); return true; } bool start_array(std::size_t elements) override { - events.push_back("start: array"); + events.push_back("start_array(elements=" + std::to_string(elements) + ")"); return true; } bool end_array() override { - events.push_back("end: array"); + events.push_back("end_array()"); return true; } bool key(string_t& val) override { - events.push_back("key: " + val); + events.push_back("key(val=" + val + ")"); return true; } bool binary(json::binary_t& val) override { - events.push_back("binary"); + events.push_back("binary(val=[...])"); return true; } bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { - events.push_back("error: " + std::string(ex.what())); + events.push_back("parse_error(position=" + std::to_string(position) + ", last_token=" + last_token + ",\n ex=" + std::string(ex.what()) + ")"); return false; } }; @@ -107,22 +107,23 @@ int main() "Width": 100 }, "Animated" : false, - "IDs": [116, 943, 234, 38793], + "IDs": [116, 943, 234, -38793], + "DeletionDate": null, "Distance": 12.723374634 } - } + }] )"; // create a SAX event consumer object sax_event_consumer sec; - // parse and serialize JSON + // parse JSON bool result = json::sax_parse(text, &sec); // output the recorded events for (auto& event : sec.events) { - std::cout << "(" << event << ") "; + std::cout << event << "\n"; } // output the result of sax_parse diff --git a/docs/examples/sax_parse.output b/docs/examples/sax_parse.output index e16c2c4de..dd2fc2f05 100644 --- a/docs/examples/sax_parse.output +++ b/docs/examples/sax_parse.output @@ -1,2 +1,37 @@ -(start: object) (key: Image) (start: object) (key: Width) (value: 800) (key: Height) (value: 600) (key: Title) (value: View from 15th Floor) (key: Thumbnail) (start: object) (key: Url) (value: http://www.example.com/image/481989943) (key: Height) (value: 125) (key: Width) (value: 100) (end: object) (key: Animated) (value: false) (key: IDs) (start: array) (value: 116) (value: 943) (value: 234) (value: 38793) (end: array) (key: Distance) (value: 12.723374634) (end: object) (end: object) -result: true +start_object(elements=18446744073709551615) +key(val=Image) +start_object(elements=18446744073709551615) +key(val=Width) +number_unsigned(val=800) +key(val=Height) +number_unsigned(val=600) +key(val=Title) +string(val=View from 15th Floor) +key(val=Thumbnail) +start_object(elements=18446744073709551615) +key(val=Url) +string(val=http://www.example.com/image/481989943) +key(val=Height) +number_unsigned(val=125) +key(val=Width) +number_unsigned(val=100) +end_object() +key(val=Animated) +boolean(val=false) +key(val=IDs) +start_array(elements=18446744073709551615) +number_unsigned(val=116) +number_unsigned(val=943) +number_unsigned(val=234) +number_integer(val=-38793) +end_array() +key(val=DeletionDate) +null() +key(val=Distance) +number_float(val=12.723375, s=12.723374634) +end_object() +end_object() +parse_error(position=460, last_token=12.723374634 } }], + ex=[json.exception.parse_error.101] parse error at line 17, column 6: syntax error while parsing value - unexpected ']'; expected end of input) + +result: false diff --git a/docs/examples/sax_parse__binary.cpp b/docs/examples/sax_parse__binary.cpp new file mode 100644 index 000000000..08bc85df6 --- /dev/null +++ b/docs/examples/sax_parse__binary.cpp @@ -0,0 +1,114 @@ +#include +#include +#include +#include + +using json = nlohmann::json; + +// a simple event consumer that collects string representations of the passed +// values; note inheriting from json::json_sax_t is not required, but can +// help not to forget a required function +class sax_event_consumer : public json::json_sax_t +{ + public: + std::vector events; + + bool null() override + { + events.push_back("null()"); + return true; + } + + bool boolean(bool val) override + { + events.push_back("boolean(val=" + std::string(val ? "true" : "false") + ")"); + return true; + } + + bool number_integer(number_integer_t val) override + { + events.push_back("number_integer(val=" + std::to_string(val) + ")"); + return true; + } + + bool number_unsigned(number_unsigned_t val) override + { + events.push_back("number_unsigned(val=" + std::to_string(val) + ")"); + return true; + } + + bool number_float(number_float_t val, const string_t& s) override + { + events.push_back("number_float(val=" + std::to_string(val) + ", s=" + s + ")"); + return true; + } + + bool string(string_t& val) override + { + events.push_back("string(val=" + val + ")"); + return true; + } + + bool start_object(std::size_t elements) override + { + events.push_back("start_object(elements=" + std::to_string(elements) + ")"); + return true; + } + + bool end_object() override + { + events.push_back("end_object()"); + return true; + } + + bool start_array(std::size_t elements) override + { + events.push_back("start_array(elements=" + std::to_string(elements) + ")"); + return true; + } + + bool end_array() override + { + events.push_back("end_array()"); + return true; + } + + bool key(string_t& val) override + { + events.push_back("key(val=" + val + ")"); + return true; + } + + bool binary(json::binary_t& val) override + { + events.push_back("binary(val=[...])"); + return true; + } + + bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override + { + events.push_back("parse_error(position=" + std::to_string(position) + ", last_token=" + last_token + ",\n ex=" + std::string(ex.what()) + ")"); + return false; + } +}; + +int main() +{ + // CBOR byte string + std::vector vec = {{0x44, 0xcA, 0xfe, 0xba, 0xbe}}; + + // create a SAX event consumer object + sax_event_consumer sec; + + // parse CBOR + bool result = json::sax_parse(vec, &sec, json::input_format_t::cbor); + + // output the recorded events + for (auto& event : sec.events) + { + std::cout << event << "\n"; + } + + // output the result of sax_parse + std::cout << "\nresult: " << std::boolalpha << result << std::endl; +} diff --git a/docs/examples/sax_parse__binary.output b/docs/examples/sax_parse__binary.output new file mode 100644 index 000000000..f88089610 --- /dev/null +++ b/docs/examples/sax_parse__binary.output @@ -0,0 +1,3 @@ +binary(val=[...]) + +result: true diff --git a/docs/examples/to_bjdata.cpp b/docs/examples/to_bjdata.cpp new file mode 100644 index 000000000..0bfe33323 --- /dev/null +++ b/docs/examples/to_bjdata.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +using json = nlohmann::json; + +// function to print BJData's diagnostic format +void print_byte(uint8_t byte) +{ + if (32 < byte and byte < 128) + { + std::cout << (char)byte; + } + else + { + std::cout << (int)byte; + } +} + +int main() +{ + // create a JSON value + json j = R"({"compact": true, "schema": false})"_json; + + // serialize it to BJData + std::vector v = json::to_bjdata(j); + + // print the vector content + for (auto& byte : v) + { + print_byte(byte); + } + std::cout << std::endl; + + // create an array of numbers + json array = {1, 2, 3, 4, 5, 6, 7, 8}; + + // serialize it to BJData using default representation + std::vector v_array = json::to_bjdata(array); + // serialize it to BJData using size optimization + std::vector v_array_size = json::to_bjdata(array, true); + // serialize it to BJData using type optimization + std::vector v_array_size_and_type = json::to_bjdata(array, true, true); + + // print the vector contents + for (auto& byte : v_array) + { + print_byte(byte); + } + std::cout << std::endl; + + for (auto& byte : v_array_size) + { + print_byte(byte); + } + std::cout << std::endl; + + for (auto& byte : v_array_size_and_type) + { + print_byte(byte); + } + std::cout << std::endl; +} diff --git a/docs/examples/to_bjdata.output b/docs/examples/to_bjdata.output new file mode 100644 index 000000000..087980cb9 --- /dev/null +++ b/docs/examples/to_bjdata.output @@ -0,0 +1,4 @@ +{i7compactTi6schemaF} +[i1i2i3i4i5i6i7i8] +[#i8i1i2i3i4i5i6i7i8 +[$i#i812345678 diff --git a/docs/mkdocs/docs/api/basic_json/at.md b/docs/mkdocs/docs/api/basic_json/at.md index dbd4cb6c9..3eea8dd15 100644 --- a/docs/mkdocs/docs/api/basic_json/at.md +++ b/docs/mkdocs/docs/api/basic_json/at.md @@ -184,6 +184,7 @@ Strong exception safety: if an exception occurs, the original value stays intact ## See also +- documentation on [checked access](../../features/element_access/checked_access.md) - see [`operator[]`](operator%5B%5D.md) for unchecked access by reference - see [`value`](value.md) for access with default value diff --git a/docs/mkdocs/docs/api/basic_json/basic_json.md b/docs/mkdocs/docs/api/basic_json/basic_json.md index 9a289d6e9..365cd7c22 100644 --- a/docs/mkdocs/docs/api/basic_json/basic_json.md +++ b/docs/mkdocs/docs/api/basic_json/basic_json.md @@ -241,7 +241,7 @@ basic_json(basic_json&& other) noexcept; - Overload 5: - !!! note + !!! note "Empty initializer list" When used without parentheses around an empty initializer list, `basic_json()` is called instead of this function, yielding the JSON `#!json null` value. diff --git a/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md b/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md index 6622d8aca..e19c3edd9 100644 --- a/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md +++ b/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md @@ -20,6 +20,23 @@ ignore store : store tagged values as binary container with subtype (for bytes 0xd8..0xdb) +## Examples + +??? example + + The example below shows how the different values of the `cbor_tag_handler_t` influence the behavior of + [`from_cbor`](from_cbor.md) when reading a tagged byte string. + + ```cpp + --8<-- "examples/cbor_tag_handler_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/cbor_tag_handler_t.output" + ``` + ## Version history - Added in version 3.9.0. Added value `store` in 3.10.0. diff --git a/docs/mkdocs/docs/api/basic_json/contains.md b/docs/mkdocs/docs/api/basic_json/contains.md index 67a5ffcc0..e6d9df85c 100644 --- a/docs/mkdocs/docs/api/basic_json/contains.md +++ b/docs/mkdocs/docs/api/basic_json/contains.md @@ -60,8 +60,8 @@ Logarithmic in the size of the JSON object. ## Notes -1. This method always returns `#!cpp false` when executed on a JSON type that is not an object. -2. This method can be executed on any JSON value type. +- This method always returns `#!cpp false` when executed on a JSON type that is not an object. +- This method can be executed on any JSON value type. !!! info "Postconditions" diff --git a/docs/mkdocs/docs/api/basic_json/default_object_comparator_t.md b/docs/mkdocs/docs/api/basic_json/default_object_comparator_t.md index 9e5f6c5bd..8a237f662 100644 --- a/docs/mkdocs/docs/api/basic_json/default_object_comparator_t.md +++ b/docs/mkdocs/docs/api/basic_json/default_object_comparator_t.md @@ -14,6 +14,22 @@ when looking up a key in an object. The actual comparator used depends on [`object_t`](object_t.md) and can be obtained via [`object_comparator_t`](object_comparator_t.md). +## Examples + +??? example + + The example below demonstrates the default comparator. + + ```cpp + --8<-- "examples/default_object_comparator_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/default_object_comparator_t.output" + ``` + ## Version history - Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/basic_json/error_handler_t.md b/docs/mkdocs/docs/api/basic_json/error_handler_t.md index afd20f89d..dc32ced9b 100644 --- a/docs/mkdocs/docs/api/basic_json/error_handler_t.md +++ b/docs/mkdocs/docs/api/basic_json/error_handler_t.md @@ -20,6 +20,23 @@ replace ignore : ignore invalid UTF-8 sequences; all bytes are copied to the output unchanged +## Examples + +??? example + + The example below shows how the different values of the `error_handler_t` influence the behavior of + [`dump`](dump.md) when reading serializing an invalid UTF-8 sequence. + + ```cpp + --8<-- "examples/error_handler_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/error_handler_t.output" + ``` + ## Version history - Added in version 3.4.0. diff --git a/docs/mkdocs/docs/api/basic_json/from_bjdata.md b/docs/mkdocs/docs/api/basic_json/from_bjdata.md new file mode 100644 index 000000000..3c5eeb351 --- /dev/null +++ b/docs/mkdocs/docs/api/basic_json/from_bjdata.md @@ -0,0 +1,93 @@ +# nlohmann::basic_json::from_bjdata + +```cpp +// (1) +template +static basic_json from_bjdata(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true); +// (2) +template +static basic_json from_bjdata(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true); +``` + +Deserializes a given input to a JSON value using the BJData (Binary JData) serialization format. + +1. Reads from a compatible input. +2. Reads from an iterator range. + +The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/bjdata.md). + +## Template parameters + +`InputType` +: A compatible input, for instance: + + - an `std::istream` object + - a `FILE` pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of iterators. + +`IteratorType` +: a compatible iterator type + +## Parameters + +`i` (in) +: an input in BJData format convertible to an input adapter + +`first` (in) +: iterator to start of the input + +`last` (in) +: iterator to end of the input + +`strict` (in) +: whether to expect the input to be consumed until EOF (`#!cpp true` by default) + +`allow_exceptions` (in) +: whether to throw exceptions in case of a parse error (optional, `#!cpp true` by default) + +## Return value + +deserialized JSON value; in case of a parse error and `allow_exceptions` set to `#!cpp false`, the return value will be +`value_t::discarded`. The latter can be checked with [`is_discarded`](is_discarded.md). + +## Exception safety + +Strong guarantee: if an exception is thrown, there are no changes in the JSON value. + +## Exceptions + +- Throws [parse_error.110](../../home/exceptions.md#jsonexceptionparse_error110) if the given input ends prematurely or + the end of file was not reached when `strict` was set to true +- Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if a parse error occurs +- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string could not be parsed + successfully + +## Complexity + +Linear in the size of the input. + +## Examples + +??? example + + The example shows the deserialization of a byte vector in BJData format to a JSON value. + + ```cpp + --8<-- "examples/from_bjdata.cpp" + ``` + + Output: + + ```json + --8<-- "examples/from_bjdata.output" + ``` + +## Version history + +- Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/basic_json/get_allocator.md b/docs/mkdocs/docs/api/basic_json/get_allocator.md index 1b7700c77..07a4d8456 100644 --- a/docs/mkdocs/docs/api/basic_json/get_allocator.md +++ b/docs/mkdocs/docs/api/basic_json/get_allocator.md @@ -10,10 +10,22 @@ Returns the allocator associated with the container. associated allocator +## Examples + +??? example + + The example shows how `get_allocator()` is used to created `json` values. + + ```cpp + --8<-- "examples/get_allocator.cpp" + ``` + + Output: + + ```json + --8<-- "examples/get_allocator.output" + ``` + ## Version history -- Unknown. - -!!! note - - This documentation page is a stub. +- Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/index.md b/docs/mkdocs/docs/api/basic_json/index.md index 68ac063ff..bc4dba153 100644 --- a/docs/mkdocs/docs/api/basic_json/index.md +++ b/docs/mkdocs/docs/api/basic_json/index.md @@ -268,10 +268,12 @@ Access to the JSON value ### Binary formats +- [**from_bjdata**](from_bjdata.md) (_static_) - create a JSON value from an input in BJData format - [**from_bson**](from_bson.md) (_static_) - create a JSON value from an input in BSON format - [**from_cbor**](from_cbor.md) (_static_) - create a JSON value from an input in CBOR format - [**from_msgpack**](from_msgpack.md) (_static_) - create a JSON value from an input in MessagePack format - [**from_ubjson**](from_ubjson.md) (_static_) - create a JSON value from an input in UBJSON format +- [**to_bjdata**](to_bjdata.md) (_static_) - create a BJData serialization of a given JSON value - [**to_bson**](to_bson.md) (_static_) - create a BSON serialization of a given JSON value - [**to_cbor**](to_cbor.md) (_static_) - create a CBOR serialization of a given JSON value - [**to_msgpack**](to_msgpack.md) (_static_) - create a MessagePack serialization of a given JSON value diff --git a/docs/mkdocs/docs/api/basic_json/input_format_t.md b/docs/mkdocs/docs/api/basic_json/input_format_t.md index 4accf6dee..a3baabab8 100644 --- a/docs/mkdocs/docs/api/basic_json/input_format_t.md +++ b/docs/mkdocs/docs/api/basic_json/input_format_t.md @@ -6,7 +6,8 @@ enum class input_format_t { cbor, msgpack, ubjson, - bson + bson, + bjdata }; ``` @@ -27,6 +28,25 @@ ubjson bson : BSON (Binary JSON) +bjdata +: BJData (Binary JData) + +## Examples + +??? example + + The example below shows how an `input_format_t` enum value is passed to `sax_parse` to set the input format to CBOR. + + ```cpp + --8<-- "examples/sax_parse__binary.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse__binary.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/basic_json/object_comparator_t.md b/docs/mkdocs/docs/api/basic_json/object_comparator_t.md index 6c64b6453..496a56267 100644 --- a/docs/mkdocs/docs/api/basic_json/object_comparator_t.md +++ b/docs/mkdocs/docs/api/basic_json/object_comparator_t.md @@ -1,6 +1,5 @@ # nlohmann::basic_json::object_comparator_t - ```cpp using object_comparator_t = typename object_t::key_compare; // or @@ -10,6 +9,22 @@ using object_comparator_t = default_object_comparator_t; The comparator used by [`object_t`](object_t.md). Defined as `#!cpp typename object_t::key_compare` if available, and [`default_object_comparator_t`](default_object_comparator_t.md) otherwise. +## Examples + +??? example + + The example below demonstrates the used object comparator. + + ```cpp + --8<-- "examples/object_comparator_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/object_comparator_t.output" + ``` + ## Version history - Added in version 3.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/operator+=.md b/docs/mkdocs/docs/api/basic_json/operator+=.md index 074b30003..dc5f2ecc4 100644 --- a/docs/mkdocs/docs/api/basic_json/operator+=.md +++ b/docs/mkdocs/docs/api/basic_json/operator+=.md @@ -41,12 +41,9 @@ reference operator+=(initializer_list_t init); ## Exceptions -1. The function can throw the following exceptions: - - Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) when called on a type other than - JSON array or null; example: `"cannot use operator+=() with number"` -2. The function can throw the following exceptions: - - Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) when called on a type other than - JSON object or null; example: `"cannot use operator+=() with number"` +All functions can throw the following exception: + - Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) when called on a type other than + JSON array or null; example: `"cannot use operator+=() with number"` ## Complexity diff --git a/docs/mkdocs/docs/api/basic_json/operator[].md b/docs/mkdocs/docs/api/basic_json/operator[].md index cd5638b97..9fa0c8999 100644 --- a/docs/mkdocs/docs/api/basic_json/operator[].md +++ b/docs/mkdocs/docs/api/basic_json/operator[].md @@ -198,6 +198,8 @@ Strong exception safety: if an exception occurs, the original value stays intact ## See also +- documentation on [unchecked access](../../features/element_access/unchecked_access.md) +- documentation on [runtime assertions](../../features/assertions.md) - see [`at`](at.md) for access by reference with range checking - see [`value`](value.md) for access with default value diff --git a/docs/mkdocs/docs/api/basic_json/operator_ValueType.md b/docs/mkdocs/docs/api/basic_json/operator_ValueType.md index 787588781..7c1901668 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_ValueType.md +++ b/docs/mkdocs/docs/api/basic_json/operator_ValueType.md @@ -56,7 +56,6 @@ Linear in the size of the JSON value. [`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). - ## Examples ??? example diff --git a/docs/mkdocs/docs/api/basic_json/operator_eq.md b/docs/mkdocs/docs/api/basic_json/operator_eq.md index 49f96b1c0..3eec4fda4 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_eq.md +++ b/docs/mkdocs/docs/api/basic_json/operator_eq.md @@ -44,13 +44,13 @@ Linear. ## Notes -!!! note +!!! note "Comparing special values" - NaN values never compare equal to themselves or to other NaN values. - JSON `#!cpp null` values are all equal. - Discarded values never compare equal to themselves. -!!! note +!!! note "Comparing floating-point numbers" Floating-point numbers inside JSON values numbers are compared with `json::number_float_t::operator==` which is `double::operator==` by default. To compare floating-point while respecting an epsilon, an alternative diff --git a/docs/mkdocs/docs/api/basic_json/push_back.md b/docs/mkdocs/docs/api/basic_json/push_back.md index 60bfed305..5c7d20dd6 100644 --- a/docs/mkdocs/docs/api/basic_json/push_back.md +++ b/docs/mkdocs/docs/api/basic_json/push_back.md @@ -37,12 +37,9 @@ void push_back(initializer_list_t init); ## Exceptions -1. The function can throw the following exceptions: - - Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) when called on a type other than - JSON array or null; example: `"cannot use push_back() with number"` -2. The function can throw the following exceptions: - - Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) when called on a type other than - JSON object or null; example: `"cannot use push_back() with number"` +All functions can throw the following exception: + - Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) when called on a type other than + JSON array or null; example: `"cannot use push_back() with number"` ## Complexity diff --git a/docs/mkdocs/docs/api/basic_json/to_bjdata.md b/docs/mkdocs/docs/api/basic_json/to_bjdata.md new file mode 100644 index 000000000..1ea850523 --- /dev/null +++ b/docs/mkdocs/docs/api/basic_json/to_bjdata.md @@ -0,0 +1,70 @@ +# nlohmann::basic_json::to_bjdata + +```cpp +// (1) +static std::vector to_bjdata(const basic_json& j, + const bool use_size = false, + const bool use_type = false); + +// (2) +static void to_bjdata(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false); +static void to_bjdata(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false); +``` + +Serializes a given JSON value `j` to a byte vector using the BJData (Binary JData) serialization format. BJData +aims to be more compact than JSON itself, yet more efficient to parse. + +1. Returns a byte vector containing the BJData serialization. +2. Writes the BJData serialization to an output adapter. + +The exact mapping and its limitations is described on a [dedicated page](../../features/binary_formats/bjdata.md). + +## Parameters + +`j` (in) +: JSON value to serialize + +`o` (in) +: output adapter to write serialization to + +`use_size` (in) +: whether to add size annotations to container types; optional, `#!cpp false` by default. + +`use_type` (in) +: whether to add type annotations to container types (must be combined with `#!cpp use_size = true`); optional, +`#!cpp false` by default. + +## Return value + +1. BJData serialization as byte vector +2. (none) + +## Exception safety + +Strong guarantee: if an exception is thrown, there are no changes in the JSON value. + +## Complexity + +Linear in the size of the JSON value `j`. + +## Examples + +??? example + + The example shows the serialization of a JSON value to a byte vector in BJData format. + + ```cpp + --8<-- "examples/to_bjdata.cpp" + ``` + + Output: + + ```json + --8<-- "examples/to_bjdata.output" + ``` + +## Version history + +- Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/basic_json/value_t.md b/docs/mkdocs/docs/api/basic_json/value_t.md index 768b13ca1..e7d32c480 100644 --- a/docs/mkdocs/docs/api/basic_json/value_t.md +++ b/docs/mkdocs/docs/api/basic_json/value_t.md @@ -29,6 +29,22 @@ distinguishes these three types for numbers: [`number_unsigned_t`](number_unsign [`number_integer_t`](number_integer_t.md) is used for signed integers, and [`number_float_t`](number_float_t.md) is used for floating-point numbers or to approximate integers which do not fit in the limits of their respective type. +## Examples + +??? example + + The following code how `type()` queries the `value_t` for all JSON types. + + ```cpp + --8<-- "examples/type.cpp" + ``` + + Output: + + ```json + --8<-- "examples/type.output" + ``` + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md index caa273df5..9913a9b5c 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md @@ -25,6 +25,22 @@ byte_container_with_subtype(container_type&& container, subtype_type subtype); `subtype` (in) : subtype +## Examples + +??? example + + The example below demonstrates how byte containers can be created. + + ```cpp + --8<-- "examples/byte_container_with_subtype__byte_container_with_subtype.cpp" + ``` + + Output: + + ```json + --8<-- "examples/byte_container_with_subtype__byte_container_with_subtype.output" + ``` + ## Version history Since version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md index 56f8ee0c1..c62dead36 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md @@ -15,6 +15,22 @@ No-throw guarantee: this function never throws exceptions. Constant. +## Examples + +??? example + + The example below demonstrates how `clear_subtype` can remove subtypes. + + ```cpp + --8<-- "examples/byte_container_with_subtype__clear_subtype.cpp" + ``` + + Output: + + ```json + --8<-- "examples/byte_container_with_subtype__clear_subtype.output" + ``` + ## Version history Since version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/has_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/has_subtype.md index 2fe418132..e06286e29 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/has_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/has_subtype.md @@ -18,6 +18,22 @@ No-throw guarantee: this function never throws exceptions. Constant. +## Examples + +??? example + + The example below demonstrates how `has_subtype` can check whether a subtype was set. + + ```cpp + --8<-- "examples/byte_container_with_subtype__has_subtype.cpp" + ``` + + Output: + + ```json + --8<-- "examples/byte_container_with_subtype__has_subtype.output" + ``` + ## Version history Since version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/set_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/set_subtype.md index 40cc2722f..cf21732b8 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/set_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/set_subtype.md @@ -20,6 +20,22 @@ No-throw guarantee: this function never throws exceptions. Constant. +## Examples + +??? example + + The example below demonstrates how a subtype can be set with `set_subtype`. + + ```cpp + --8<-- "examples/byte_container_with_subtype__set_subtype.cpp" + ``` + + Output: + + ```json + --8<-- "examples/byte_container_with_subtype__set_subtype.output" + ``` + ## Version history Since version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/subtype.md index e78654b37..389241a79 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/subtype.md @@ -19,6 +19,23 @@ No-throw guarantee: this function never throws exceptions. Constant. +## Examples + +??? example + + The example below demonstrates how the subtype can be retrieved with `subtype`. Note how `subtype_type(-1)` is + returned for container `c1`. + + ```cpp + --8<-- "examples/byte_container_with_subtype__subtype.cpp" + ``` + + Output: + + ```json + --8<-- "examples/byte_container_with_subtype__subtype.output" + ``` + ## Version history - Added in version 3.8.0 diff --git a/docs/mkdocs/docs/api/json.md b/docs/mkdocs/docs/api/json.md index 48d344183..36edcc2c1 100644 --- a/docs/mkdocs/docs/api/json.md +++ b/docs/mkdocs/docs/api/json.md @@ -7,6 +7,22 @@ using json = basic_json<>; This type is the default specialization of the [basic_json](basic_json/index.md) class which uses the standard template types. +## Examples + +??? example + + The example below demonstrates how to use the type `nlohmann::json`. + + ```cpp + --8<-- "examples/README.cpp" + ``` + + Output: + + ```json + --8<-- "examples/README.output" + ``` + ## Version history Since version 1.0.0. diff --git a/docs/mkdocs/docs/api/json_pointer/index.md b/docs/mkdocs/docs/api/json_pointer/index.md index dca9c382c..dc07d89b3 100644 --- a/docs/mkdocs/docs/api/json_pointer/index.md +++ b/docs/mkdocs/docs/api/json_pointer/index.md @@ -14,11 +14,11 @@ are the base for JSON patches. `RefStringType` : the string type used for the reference tokens making up the JSON pointer -## Notes +!!! warning "Deprecation" -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 diff --git a/docs/mkdocs/docs/api/json_pointer/operator_string.md b/docs/mkdocs/docs/api/json_pointer/operator_string.md index 836728c18..f2f99cae7 100644 --- a/docs/mkdocs/docs/api/json_pointer/operator_string.md +++ b/docs/mkdocs/docs/api/json_pointer/operator_string.md @@ -19,6 +19,22 @@ operator string_t() const } ``` +## Examples + +??? example + + The example shows how JSON Pointers can be implicitly converted to strings. + + ```cpp + --8<-- "examples/json_pointer__operator_string.cpp" + ``` + + Output: + + ```json + --8<-- "examples/json_pointer__operator_string.output" + ``` + ## Version history - Since version 2.0.0. diff --git a/docs/mkdocs/docs/api/json_pointer/string_t.md b/docs/mkdocs/docs/api/json_pointer/string_t.md index f18b51b81..c8527bc9c 100644 --- a/docs/mkdocs/docs/api/json_pointer/string_t.md +++ b/docs/mkdocs/docs/api/json_pointer/string_t.md @@ -7,6 +7,22 @@ The string type used for the reference tokens making up the JSON pointer. See [`basic_json::string_t`](../basic_json/string_t.md) for more information. +## Examples + +??? example + + The example shows the type `string_t` and its relation to `basic_json::string_t`. + + ```cpp + --8<-- "examples/json_pointer__string_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/json_pointer__string_t.output" + ``` + ## Version history - Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/json_sax/binary.md b/docs/mkdocs/docs/api/json_sax/binary.md index e9a1d3974..753e99c00 100644 --- a/docs/mkdocs/docs/api/json_sax/binary.md +++ b/docs/mkdocs/docs/api/json_sax/binary.md @@ -19,6 +19,22 @@ Whether parsing should proceed. It is safe to move the passed binary value. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse__binary.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse__binary.output" + ``` + ## Version history - Added in version 3.8.0. diff --git a/docs/mkdocs/docs/api/json_sax/boolean.md b/docs/mkdocs/docs/api/json_sax/boolean.md index a5a8ddcb7..78163b331 100644 --- a/docs/mkdocs/docs/api/json_sax/boolean.md +++ b/docs/mkdocs/docs/api/json_sax/boolean.md @@ -15,6 +15,22 @@ A boolean value was read. Whether parsing should proceed. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/end_array.md b/docs/mkdocs/docs/api/json_sax/end_array.md index 245cf974c..46b4c7a4b 100644 --- a/docs/mkdocs/docs/api/json_sax/end_array.md +++ b/docs/mkdocs/docs/api/json_sax/end_array.md @@ -10,6 +10,22 @@ The end of an array was read. Whether parsing should proceed. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/end_object.md b/docs/mkdocs/docs/api/json_sax/end_object.md index 5654e262e..8df0ab4e1 100644 --- a/docs/mkdocs/docs/api/json_sax/end_object.md +++ b/docs/mkdocs/docs/api/json_sax/end_object.md @@ -10,6 +10,22 @@ The end of an object was read. Whether parsing should proceed. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/key.md b/docs/mkdocs/docs/api/json_sax/key.md index 5e7927256..ebd3ae2b2 100644 --- a/docs/mkdocs/docs/api/json_sax/key.md +++ b/docs/mkdocs/docs/api/json_sax/key.md @@ -19,6 +19,22 @@ Whether parsing should proceed. It is safe to move the passed object key value. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/null.md b/docs/mkdocs/docs/api/json_sax/null.md index bcbb4a348..71b2a458a 100644 --- a/docs/mkdocs/docs/api/json_sax/null.md +++ b/docs/mkdocs/docs/api/json_sax/null.md @@ -10,6 +10,22 @@ A null value was read. Whether parsing should proceed. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/number_float.md b/docs/mkdocs/docs/api/json_sax/number_float.md index 94193280b..e1b3fb60f 100644 --- a/docs/mkdocs/docs/api/json_sax/number_float.md +++ b/docs/mkdocs/docs/api/json_sax/number_float.md @@ -18,6 +18,22 @@ A floating-point number was read. Whether parsing should proceed. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/number_integer.md b/docs/mkdocs/docs/api/json_sax/number_integer.md index 00ff2eaa6..8628a655c 100644 --- a/docs/mkdocs/docs/api/json_sax/number_integer.md +++ b/docs/mkdocs/docs/api/json_sax/number_integer.md @@ -15,6 +15,22 @@ An integer number was read. Whether parsing should proceed. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/number_unsigned.md b/docs/mkdocs/docs/api/json_sax/number_unsigned.md index 66d0bdac4..7b5974823 100644 --- a/docs/mkdocs/docs/api/json_sax/number_unsigned.md +++ b/docs/mkdocs/docs/api/json_sax/number_unsigned.md @@ -15,6 +15,22 @@ An unsigned integer number was read. Whether parsing should proceed. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/parse_error.md b/docs/mkdocs/docs/api/json_sax/parse_error.md index 00f1aa950..d4405d09e 100644 --- a/docs/mkdocs/docs/api/json_sax/parse_error.md +++ b/docs/mkdocs/docs/api/json_sax/parse_error.md @@ -23,6 +23,22 @@ A parse error occurred. Whether parsing should proceed (**must return `#!cpp false`**). +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/start_array.md b/docs/mkdocs/docs/api/json_sax/start_array.md index d10a6e5a6..8ef10a4ab 100644 --- a/docs/mkdocs/docs/api/json_sax/start_array.md +++ b/docs/mkdocs/docs/api/json_sax/start_array.md @@ -19,6 +19,22 @@ Whether parsing should proceed. Binary formats may report the number of elements. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/start_object.md b/docs/mkdocs/docs/api/json_sax/start_object.md index fd90f1947..24fedffc3 100644 --- a/docs/mkdocs/docs/api/json_sax/start_object.md +++ b/docs/mkdocs/docs/api/json_sax/start_object.md @@ -19,6 +19,22 @@ Whether parsing should proceed. Binary formats may report the number of elements. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/string.md b/docs/mkdocs/docs/api/json_sax/string.md index 113fe1393..1cb6014ac 100644 --- a/docs/mkdocs/docs/api/json_sax/string.md +++ b/docs/mkdocs/docs/api/json_sax/string.md @@ -19,6 +19,22 @@ Whether parsing should proceed. It is safe to move the passed string value. +## Examples + +??? example + + .The example below shows how the SAX interface is used. + + ```cpp + --8<-- "examples/sax_parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/sax_parse.output" + ``` + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/macros/json_has_cpp_11.md b/docs/mkdocs/docs/api/macros/json_has_cpp_11.md index 3bee84324..f3eaa585c 100644 --- a/docs/mkdocs/docs/api/macros/json_has_cpp_11.md +++ b/docs/mkdocs/docs/api/macros/json_has_cpp_11.md @@ -23,6 +23,19 @@ The default value is detected based on preprocessor macros such as `#!cpp __cplu - `#!cpp JSON_HAS_CPP_11` is always defined. - All macros are undefined outside the library. +## Examples + +??? example + + The code below forces the library to use the C++14 standard: + + ```cpp + #define JSON_HAS_CPP_14 1 + #include + + ... + ``` + ## Version history - Added in version 3.10.5. diff --git a/docs/mkdocs/docs/api/macros/json_has_filesystem.md b/docs/mkdocs/docs/api/macros/json_has_filesystem.md index 160ad8c24..308aea2ac 100644 --- a/docs/mkdocs/docs/api/macros/json_has_filesystem.md +++ b/docs/mkdocs/docs/api/macros/json_has_filesystem.md @@ -25,6 +25,19 @@ The default value is detected based on the preprocessor macros `#!cpp __cpp_lib_ filesystem support. - Both macros are undefined outside the library. +## Examples + +??? example + + The code below forces the library to use the header ``. + + ```cpp + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #include + + ... + ``` + ## Version history - Added in version 3.10.5. diff --git a/docs/mkdocs/docs/api/macros/json_no_io.md b/docs/mkdocs/docs/api/macros/json_no_io.md index 10ae24c8a..ef37384a5 100644 --- a/docs/mkdocs/docs/api/macros/json_no_io.md +++ b/docs/mkdocs/docs/api/macros/json_no_io.md @@ -16,6 +16,20 @@ By default, `#!cpp JSON_NO_IO` is not defined. #undef JSON_NO_IO ``` +## Examples + +??? example + + The code below forces the library not to use the headers ``, ``, ``, ``, and + ``. + + ```cpp + #define JSON_NO_IO 1 + #include + + ... + ``` + ## Version history - Added in version 3.10.0. diff --git a/docs/mkdocs/docs/api/macros/json_noexception.md b/docs/mkdocs/docs/api/macros/json_noexception.md index 0f32b63e9..c801b8567 100644 --- a/docs/mkdocs/docs/api/macros/json_noexception.md +++ b/docs/mkdocs/docs/api/macros/json_noexception.md @@ -23,6 +23,19 @@ By default, the macro is not defined. 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). +## Examples + +??? example + + The code below switches off exceptions in the library. + + ```cpp + #define JSON_NOEXCEPTION 1 + #include + + ... + ``` + ## See also - [Switch off exceptions](../../home/exceptions.md#switch-off-exceptions) for more information how to switch off exceptions diff --git a/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md b/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md index c58d0ea85..374fa4c27 100644 --- a/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md +++ b/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md @@ -15,6 +15,19 @@ By default, the macro is not defined. #undef JSON_SKIP_UNSUPPORTED_COMPILER_CHECK ``` +## Examples + +??? example + + The code below switches off the check whether the compiler is supported. + + ```cpp + #define JSON_SKIP_UNSUPPORTED_COMPILER_CHECK 1 + #include + + ... + ``` + ## Version history Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_version_major.md b/docs/mkdocs/docs/api/macros/nlohmann_json_version_major.md index 826785292..d7a314276 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_json_version_major.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_version_major.md @@ -13,6 +13,23 @@ These macros are defined by the library and contain the version numbers accordin The macros are defined according to the current library version. +## Examples + +??? example + + The example below shows how `NLOHMANN_JSON_VERSION_MAJOR`, `NLOHMANN_JSON_VERSION_MINOR`, and + `NLOHMANN_JSON_VERSION_PATCH` are defined by the library. + + ```cpp + --8<-- "examples/nlohmann_json_version.cpp" + ``` + + Output: + + ```json + --8<-- "examples/nlohmann_json_version.output" + ``` + ## See also - [meta](../basic_json/meta.md) - returns version information on the library diff --git a/docs/mkdocs/docs/api/ordered_json.md b/docs/mkdocs/docs/api/ordered_json.md index 8b122f90b..7cfd9f4dd 100644 --- a/docs/mkdocs/docs/api/ordered_json.md +++ b/docs/mkdocs/docs/api/ordered_json.md @@ -6,9 +6,26 @@ using ordered_json = basic_json; This type preserves the insertion order of object keys. +## Examples + +??? example + + The example below demonstrates how `ordered_json` preserves the insertion order of object keys. + + ```cpp + --8<-- "examples/ordered_json.cpp" + ``` + + Output: + + ```json + --8<-- "examples/ordered_json.output" + ``` + ## See also - [ordered_map](ordered_map.md) +- [Object Order](../features/object_order.md) ## Version history diff --git a/docs/mkdocs/docs/features/binary_formats/bjdata.md b/docs/mkdocs/docs/features/binary_formats/bjdata.md new file mode 100644 index 000000000..fae55658f --- /dev/null +++ b/docs/mkdocs/docs/features/binary_formats/bjdata.md @@ -0,0 +1,209 @@ +# BJData + +The [BJData format](https://neurojson.org) was derived from and improved upon +[Universal Binary JSON(UBJSON)](https://ubjson.org) specification (Draft 12). +Specifically, it introduces an optimized array container for efficient storage +of N-dimensional packed arrays (**ND-arrays**); it also adds 4 new type markers - +`[u] - uint16`, `[m] - uint32`, `[M] - uint64` and `[h] - float16` - to +unambigiously map common binary numeric types; furthermore, it uses little-endian +(LE) to store all numerics instead of big-endian (BE) as in UBJSON to avoid +unnecessary conversions on commonly available platforms. + +Compared to other binary-JSON-like formats such as MessagePack and CBOR, both BJData and +UBJSON demonstrate a rare combination of being both binary and **quasi-human-readable**. This +is because all semantic elements in BJData and UBJSON, including the data-type markers +and name/string types are directly human-readable. Data stored in the BJData/UBJSON format +are not only compact in size, fast to read/write, but also can be directly searched +or read using simple processing. + +!!! abstract "References" + + - [BJData Specification](https://neurojson.org/bjdata/draft2) + +## Serialization + +The library uses the following mapping from JSON values types to BJData types according to the BJData specification: + +| JSON value type | value/range | BJData type | marker | +|-----------------|-------------------------------------------|----------------|--------| +| null | `null` | null | `Z` | +| boolean | `true` | true | `T` | +| boolean | `false` | false | `F` | +| number_integer | -9223372036854775808..-2147483649 | int64 | `L` | +| number_integer | -2147483648..-32769 | int32 | `l` | +| number_integer | -32768..-129 | int16 | `I` | +| number_integer | -128..127 | int8 | `i` | +| number_integer | 128..255 | uint8 | `U` | +| number_integer | 256..32767 | int16 | `I` | +| number_integer | 32768..65535 | uint16 | `u` | +| number_integer | 65536..2147483647 | int32 | `l` | +| number_integer | 2147483648..4294967295 | uint32 | `m` | +| number_integer | 4294967296..9223372036854775807 | int64 | `L` | +| number_integer | 9223372036854775808..18446744073709551615 | uint64 | `M` | +| number_unsigned | 0..127 | int8 | `i` | +| number_unsigned | 128..255 | uint8 | `U` | +| number_unsigned | 256..32767 | int16 | `I` | +| number_unsigned | 32768..65535 | uint16 | `u` | +| number_unsigned | 65536..2147483647 | int32 | `l` | +| number_unsigned | 2147483648..4294967295 | uint32 | `m` | +| number_unsigned | 4294967296..9223372036854775807 | int64 | `L` | +| number_unsigned | 9223372036854775808..18446744073709551615 | uint64 | `M` | +| number_float | *any value* | float64 | `D` | +| string | *with shortest length indicator* | string | `S` | +| array | *see notes on optimized format/ND-array* | array | `[` | +| object | *see notes on optimized format* | map | `{` | + +!!! success "Complete mapping" + + The mapping is **complete** in the sense that any JSON value type can be converted to a BJData value. + + Any BJData output created by `to_bjdata` can be successfully parsed by `from_bjdata`. + +!!! warning "Size constraints" + + The following values can **not** be converted to a BJData value: + + - strings with more than 18446744073709551615 bytes (theoretical) + +!!! info "Unused BJData markers" + + The following markers are not used in the conversion: + + - `Z`: no-op values are not created. + - `C`: single-byte strings are serialized with `S` markers. + +!!! info "NaN/infinity handling" + + If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the `dump()` + function which serializes NaN or Infinity to `null`. + + +!!! info "Endianness" + + A breaking difference between BJData and UBJSON is the endianness + of numerical values. In BJData, all numerical data types (integers + `UiuImlML` and floating-point values `hdD`) are stored in the little-endian (LE) + byte order as opposed to big-endian as used by UBJSON. To adopt LE + to store numeric records avoids unnecessary byte swapping on most modern + computers where LE is used as the default byte order. + +!!! info "Optimized formats" + + The optimized formats for containers are supported: Parameter + `use_size` adds size information to the beginning of a container and + removes the closing marker. Parameter `use_type` further checks + whether all elements of a container have the same type and adds the + type marker to the beginning of the container. The `use_type` + parameter must only be used together with `use_size = true`. + + Note that `use_size = true` alone may result in larger representations - + the benefit of this parameter is that the receiving side is + immediately informed on the number of elements of the container. + +!!! info "ND-array optimized format" + + BJData extends UBJSON's optimized array **size** marker to support + ND-array of uniform numerical data types (referred to as the *packed array*). + For example, 2-D `uint8` integer array `[[1,2],[3,4],[5,6]]` that can be stored + as nested optimized array in UBJSON `[ [$U#i2 1 2 [$U#i2 3 4 [$U#i2 5 6 ]`, + can be further compressed in BJData and stored as `[$U#[$i#i2 2 3 1 2 3 4 5 6` + or `[$U#[i2 i3] 1 2 3 4 5 6`. + + In order to maintain the type and dimension information of an ND-array, + when this library parses a BJData ND-array via `from_bjdata`, it converts the + data into a JSON object, following the **annotated array format** as defined in the + [JData specification (Draft 3)](https://github.com/NeuroJSON/jdata/blob/master/JData_specification.md#annotated-storage-of-n-d-arrays). + For example, the above 2-D `uint8` array can be parsed and accessed as + + ```json + { + "_ArrayType_": "uint8", + "_ArraySize_": [2,3], + "_ArrayData_": [1,2,3,4,5,6] + } + ``` + + In the reversed direction, when `to_bjdata` detects a JSON object in the + above form, it automatically converts such object into a BJData ND-array + to generate compact output. The only exception is that when the 1-D dimensional + vector stored in `"_ArraySize_"` contains a single integer, or two integers with + one being 1, a regular 1-D optimized array is generated. + + The current version of this library has not yet supported automatic + recognition and conversion from a nested JSON array input to a BJData ND-array. + +!!! info "Restrictions in optimized data types for arrays and objects" + + Due to diminished space saving, hampered readability, and increased + security risks, in BJData, the allowed data types following the `$` marker + in an optimized array and object container are restricted to + **non-zero-fixed-length** data types. Therefore, the valid optimized + type markers can only be one of `UiuImlMLhdDC`. This also means other + variable (`[{SH`) or zero-length types (`TFN`) can not be used in an + optimized array or object in BJData. + +!!! info "Binary values" + + If the JSON data contains the binary type, the value stored is a list + of integers, as suggested by the BJData documentation. In particular, + this means that serialization and the deserialization of a JSON + containing binary values into BJData and back will result in a + different JSON object. + + +??? example + + ```cpp + --8<-- "examples/to_bjdata.cpp" + ``` + + Output: + + ```c + --8<-- "examples/to_bjdata.output" + ``` + +## Deserialization + +The library maps BJData types to JSON value types as follows: + +| BJData type | JSON value type | marker | +|-------------|-----------------------------------------|--------| +| no-op | *no value, next value is read* | `N` | +| null | `null` | `Z` | +| false | `false` | `F` | +| true | `true` | `T` | +| float16 | number_float | `h` | +| float32 | number_float | `d` | +| float64 | number_float | `D` | +| uint8 | number_unsigned | `U` | +| int8 | number_integer | `i` | +| uint16 | number_unsigned | `u` | +| int16 | number_integer | `I` | +| uint32 | number_unsigned | `m` | +| int32 | number_integer | `l` | +| uint64 | number_unsigned | `M` | +| int64 | number_integer | `L` | +| string | string | `S` | +| char | string | `C` | +| array | array (optimized values are supported) | `[` | +| ND-array | object (in JData annotated array format)|`[$.#[.`| +| object | object (optimized values are supported) | `{` | + +!!! success "Complete mapping" + + The mapping is **complete** in the sense that any BJData value can be converted to a JSON value. + + +??? example + + ```cpp + --8<-- "examples/from_bjdata.cpp" + ``` + + Output: + + ```json + --8<-- "examples/from_bjdata.output" + ``` diff --git a/docs/mkdocs/docs/features/binary_formats/index.md b/docs/mkdocs/docs/features/binary_formats/index.md index 3a969a5dc..e74290b09 100644 --- a/docs/mkdocs/docs/features/binary_formats/index.md +++ b/docs/mkdocs/docs/features/binary_formats/index.md @@ -1,7 +1,9 @@ # Binary Formats -Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports +Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over +a network. Hence, the library supports +- [BJData](bjdata.md) (Binary JData), - [BSON](bson.md) (Binary JSON), - [CBOR](cbor.md) (Concise Binary Object Representation), - [MessagePack](messagepack.md), and @@ -15,6 +17,7 @@ to efficiently encode JSON values to byte vectors and to decode such vectors. | Format | Serialization | Deserialization | |-------------|-----------------------------------------------|----------------------------------------------| +| BJData | complete | complete | | BSON | incomplete: top-level value must be an object | incomplete, but all JSON types are supported | | CBOR | complete | incomplete, but all JSON types are supported | | MessagePack | complete | complete | @@ -24,6 +27,7 @@ to efficiently encode JSON values to byte vectors and to decode such vectors. | Format | Binary values | Binary subtypes | |-------------|---------------|-----------------| +| BJData | not supported | not supported | | BSON | supported | supported | | CBOR | supported | supported | | MessagePack | supported | supported | @@ -35,11 +39,14 @@ See [binary values](../binary_values.md) for more information. | Format | canada.json | twitter.json | citm_catalog.json | jeopardy.json | |--------------------|-------------|--------------|-------------------|---------------| -| BSON | 85,8 % | 95,2 % | 95,8 % | 106,7 % | -| CBOR | 50,5 % | 86,3 % | 68,4 % | 88,0 % | -| MessagePack | 50,6 % | 86,0 % | 68,5 % | 87,9 % | -| UBJSON | 53,2 % | 91,3 % | 78,2 % | 96,6 % | -| UBJSON (size) | 58,6 % | 92,3 % | 86,8 % | 97,4 % | -| UBJSON (size+type) | 55,9 % | 92,3 % | 85,0 % | 95,0 % | +| BJData | 53.2 % | 91.1 % | 78.1 % | 96.6 % | +| BJData (size) | 58.6 % | 92.1 % | 86.7 % | 97.4 % | +| BJData (size+tyoe) | 58.6 % | 92.1 % | 86.5 % | 97.4 % | +| BSON | 85.8 % | 95.2 % | 95.8 % | 106.7 % | +| CBOR | 50.5 % | 86.3 % | 68.4 % | 88.0 % | +| MessagePack | 50.5 % | 86.0 % | 68.5 % | 87.9 % | +| UBJSON | 53.2 % | 91.3 % | 78.2 % | 96.6 % | +| UBJSON (size) | 58.6 % | 92.3 % | 86.8 % | 97.4 % | +| UBJSON (size+type) | 55.9 % | 92.3 % | 85.0 % | 95.0 % | Sizes compared to minified JSON value. diff --git a/docs/mkdocs/docs/features/binary_values.md b/docs/mkdocs/docs/features/binary_values.md index c58834c05..5ad6433cf 100644 --- a/docs/mkdocs/docs/features/binary_values.md +++ b/docs/mkdocs/docs/features/binary_values.md @@ -1,8 +1,12 @@ # Binary Values -The library implements several [binary formats](binary_formats/index.md) that encode JSON in an efficient way. Most of these formats support binary values; that is, values that have semantics define outside the library and only define a sequence of bytes to be stored. +The library implements several [binary formats](binary_formats/index.md) that encode JSON in an efficient way. Most of +these formats support binary values; that is, values that have semantics define outside the library and only define a +sequence of bytes to be stored. -JSON itself does not have a binary value. As such, binary values are an extension that this library implements to store values received by a binary format. Binary values are never created by the JSON parser, and are only part of a serialized JSON text if they have been created manually or via a binary format. +JSON itself does not have a binary value. As such, binary values are an extension that this library implements to store +values received by a binary format. Binary values are never created by the JSON parser, and are only part of a +serialized JSON text if they have been created manually or via a binary format. ## API for binary values @@ -19,7 +23,9 @@ class json::binary_t { "std::vector" <|-- json::binary_t ``` -By default, binary values are stored as `std::vector`. This type can be changed by providing a template parameter to the `basic_json` type. To store binary subtypes, the storage type is extended and exposed as `json::binary_t`: +By default, binary values are stored as `std::vector`. This type can be changed by providing a template +parameter to the `basic_json` type. To store binary subtypes, the storage type is extended and exposed as +`json::binary_t`: ```cpp auto binary = json::binary_t({0xCA, 0xFE, 0xBA, 0xBE}); @@ -87,7 +93,9 @@ Binary values are serialized differently according to the formats. ### JSON -JSON does not have a binary type, and this library does not introduce a new type as this would break conformance. Instead, binary values are serialized as an object with two keys: `bytes` holds an array of integers, and `subtype` is an integer or `null`. +JSON does not have a binary type, and this library does not introduce a new type as this would break conformance. +Instead, binary values are serialized as an object with two keys: `bytes` holds an array of integers, and `subtype` +is an integer or `null`. ??? example @@ -115,11 +123,72 @@ JSON does not have a binary type, and this library does not introduce a new type !!! warning "No roundtrip for binary values" - The JSON parser will not parse the objects generated by binary values back to binary values. This is by design to remain standards compliant. Serializing binary values to JSON is only implemented for debugging purposes. + The JSON parser will not parse the objects generated by binary values back to binary values. This is by design to + remain standards compliant. Serializing binary values to JSON is only implemented for debugging purposes. + +### BJData + +[BJData](binary_formats/bjdata.md) neither supports binary values nor subtypes, and proposes to serialize binary values +as array of uint8 values. This translation is implemented by the library. + +??? example + + Code: + + ```cpp + // create a binary value of subtype 42 (will be ignored in BJData) + json j; + j["binary"] = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 42); + + // convert to BJData + auto v = json::to_bjdata(j); + ``` + + `v` is a `std::vector` with the following 20 elements: + + ```c + 0x7B // '{' + 0x69 0x06 // i 6 (length of the key) + 0x62 0x69 0x6E 0x61 0x72 0x79 // "binary" + 0x5B // '[' + 0x55 0xCA 0x55 0xFE 0x55 0xBA 0x55 0xBE // content (each byte prefixed with 'U') + 0x5D // ']' + 0x7D // '}' + ``` + + The following code uses the type and size optimization for UBJSON: + + ```cpp + // convert to UBJSON using the size and type optimization + auto v = json::to_bjdata(j, true, true); + ``` + + The resulting vector has 22 elements; the optimization is not effective for examples with few values: + + ```c + 0x7B // '{' + 0x23 0x69 0x01 // '#' 'i' type of the array elements: unsigned integers + 0x69 0x06 // i 6 (length of the key) + 0x62 0x69 0x6E 0x61 0x72 0x79 // "binary" + 0x5B // '[' array + 0x24 0x55 // '$' 'U' type of the array elements: unsigned integers + 0x23 0x69 0x04 // '#' i 4 number of array elements + 0xCA 0xFE 0xBA 0xBE // content + ``` + + Note that subtype (42) is **not** serialized and that UBJSON has **no binary type**, and deserializing `v` would + yield the following value: + + ```json + { + "binary": [202, 254, 186, 190] + } + ``` ### BSON -[BSON](binary_formats/bson.md) supports binary values and subtypes. If a subtype is given, it is used and added as unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00 is used. +[BSON](binary_formats/bson.md) supports binary values and subtypes. If a subtype is given, it is used and added as +unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00 is used. ??? example @@ -159,7 +228,9 @@ JSON does not have a binary type, and this library does not introduce a new type ### CBOR -[CBOR](binary_formats/cbor.md) supports binary values, but no subtypes. Subtypes will be serialized as tags. Any binary value will be serialized as byte strings. The library will choose the smallest representation using the length of the byte array. +[CBOR](binary_formats/cbor.md) supports binary values, but no subtypes. Subtypes will be serialized as tags. Any binary +value will be serialized as byte strings. The library will choose the smallest representation using the length of the +byte array. ??? example @@ -185,7 +256,8 @@ JSON does not have a binary type, and this library does not introduce a new type 0xCA 0xFE 0xBA 0xBE // content ``` - Note that the subtype is serialized as tag. However, parsing tagged values yield a parse error unless `json::cbor_tag_handler_t::ignore` or `json::cbor_tag_handler_t::store` is passed to `json::from_cbor`. + Note that the subtype is serialized as tag. However, parsing tagged values yield a parse error unless + `json::cbor_tag_handler_t::ignore` or `json::cbor_tag_handler_t::store` is passed to `json::from_cbor`. ```json { @@ -198,7 +270,9 @@ JSON does not have a binary type, and this library does not introduce a new type ### MessagePack -[MessagePack](binary_formats/messagepack.md) supports binary values and subtypes. If a subtype is given, the ext family is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, ext8, ext16, and ext32. The subtype is then added as signed 8-bit integer. +[MessagePack](binary_formats/messagepack.md) supports binary values and subtypes. If a subtype is given, the ext family +is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, ext8, ext16, and +ext32. The subtype is then added as signed 8-bit integer. If no subtype is given, the bin family (bin8, bin16, bin32) is used. @@ -239,7 +313,8 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used. ### UBJSON -[UBJSON](binary_formats/ubjson.md) neither supports binary values nor subtypes, and proposes to serialize binary values as array of uint8 values. This translation is implemented by the library. +[UBJSON](binary_formats/ubjson.md) neither supports binary values nor subtypes, and proposes to serialize binary values +as array of uint8 values. This translation is implemented by the library. ??? example @@ -251,7 +326,7 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used. j["binary"] = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 42); // convert to UBJSON - auto v = json::to_msgpack(j); + auto v = json::to_ubjson(j); ``` `v` is a `std::vector` with the following 20 elements: @@ -287,7 +362,8 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used. 0xCA 0xFE 0xBA 0xBE // content ``` - Note that subtype (42) is **not** serialized and that UBJSON has **no binary type**, and deserializing `v` would yield the following value: + Note that subtype (42) is **not** serialized and that UBJSON has **no binary type**, and deserializing `v` would + yield the following value: ```json { diff --git a/docs/mkdocs/docs/features/element_access/checked_access.md b/docs/mkdocs/docs/features/element_access/checked_access.md index fd444bebe..c4023cce5 100644 --- a/docs/mkdocs/docs/features/element_access/checked_access.md +++ b/docs/mkdocs/docs/features/element_access/checked_access.md @@ -2,9 +2,11 @@ ## Overview -The `#!cpp at()` member function performs checked access; that is, it returns a reference to the desired value if it exists and throws a [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range) otherwise. +The [`at`](../../api/basic_json/at.md) member function performs checked access; that is, it returns a reference to the +desired value if it exists and throws a [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range) +otherwise. -??? example +??? example "Read access" Consider the following JSON value: @@ -18,18 +20,18 @@ The `#!cpp at()` member function performs checked access; that is, it returns a Assume the value is parsed to a `json` variable `j`. - | expression | value | - | ---------- | ----- | - | `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` | - | `#!cpp j.at("name")` | `#!json "Mary Smith"` | - | `#!cpp j.at("age")` | `#!json 42` | - | `#!cpp j.at("hobbies")` | `#!json ["hiking", "reading"]` | - | `#!cpp j.at("hobbies").at(0)` | `#!json "hiking"` | - | `#!cpp j.at("hobbies").at(1)` | `#!json "reading"` | + | expression | value | + |-------------------------------|------------------------------------------------------------------------------| + | `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` | + | `#!cpp j.at("name")` | `#!json "Mary Smith"` | + | `#!cpp j.at("age")` | `#!json 42` | + | `#!cpp j.at("hobbies")` | `#!json ["hiking", "reading"]` | + | `#!cpp j.at("hobbies").at(0)` | `#!json "hiking"` | + | `#!cpp j.at("hobbies").at(1)` | `#!json "reading"` | The return value is a reference, so it can be modified by the original value. -??? example +??? example "Write access" ```cpp j.at("name") = "John Smith"; @@ -45,9 +47,10 @@ The return value is a reference, so it can be modified by the original value. } ``` -When accessing an invalid index (i.e., an index greater than or equal to the array size) or the passed object key is non-existing, an exception is thrown. +When accessing an invalid index (i.e., an index greater than or equal to the array size) or the passed object key is +non-existing, an exception is thrown. -??? example +??? example "Accessing via invalid index or missing key" ```cpp j.at("hobbies").at(3) = "cooking"; @@ -59,13 +62,24 @@ When accessing an invalid index (i.e., an index greater than or equal to the arr [json.exception.out_of_range.401] array index 3 is out of range ``` + When you [extended diagnostic messages](../../home/exceptions.md#extended-diagnostic-messages) are enabled by + defining [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md), the exception further gives information where + the key or index is missing or out of range. + + ``` + [json.exception.out_of_range.401] (/hobbies) array index 3 is out of range + ``` + ## Notes !!! failure "Exceptions" - - `at` can only be used with objects (with a string argument) or with arrays (with a numeric argument). For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error304) is thrown. - - [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range) exceptions are thrown if the provided key is not found in an object or the provided index is invalid. + - [`at`](../../api/basic_json/at.md) can only be used with objects (with a string argument) or with arrays (with a + numeric argument). For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error304) + is thrown. + - [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range) exceptions are thrown if the + provided key is not found in an object or the provided index is invalid. ## Summary diff --git a/docs/mkdocs/docs/features/element_access/unchecked_access.md b/docs/mkdocs/docs/features/element_access/unchecked_access.md index 4fdef35c7..1bdea94e7 100644 --- a/docs/mkdocs/docs/features/element_access/unchecked_access.md +++ b/docs/mkdocs/docs/features/element_access/unchecked_access.md @@ -2,9 +2,10 @@ ## Overview -Elements in a JSON object and a JSON array can be accessed via `#!cpp operator[]` similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively. +Elements in a JSON object and a JSON array can be accessed via [`operator[]`](../../api/basic_json/operator%5B%5D.md) +similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively. -??? example +??? example "Read access" Consider the following JSON value: @@ -18,18 +19,19 @@ Elements in a JSON object and a JSON array can be accessed via `#!cpp operator[] Assume the value is parsed to a `json` variable `j`. - | expression | value | - | ---------- | ----- | - | `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` | - | `#!cpp j["name"]` | `#!json "Mary Smith"` | - | `#!cpp j["age"]` | `#!json 42` | - | `#!cpp j["hobbies"]` | `#!json ["hiking", "reading"]` | - | `#!cpp j["hobbies"][0]` | `#!json "hiking"` | - | `#!cpp j["hobbies"][1]` | `#!json "reading"` | + | expression | value | + |-------------------------|------------------------------------------------------------------------------| + | `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` | + | `#!cpp j["name"]` | `#!json "Mary Smith"` | + | `#!cpp j["age"]` | `#!json 42` | + | `#!cpp j["hobbies"]` | `#!json ["hiking", "reading"]` | + | `#!cpp j["hobbies"][0]` | `#!json "hiking"` | + | `#!cpp j["hobbies"][1]` | `#!json "reading"` | -The return value is a reference, so it can modify the original value. In case the passed object key is non-existing, a `#!json null` value is inserted which can be immediately be overwritten. +The return value is a reference, so it can modify the original value. In case the passed object key is non-existing, a +`#!json null` value is inserted which can be immediately be overwritten. -??? example +??? example "Write access" ```cpp j["name"] = "John Smith"; @@ -47,9 +49,10 @@ The return value is a reference, so it can modify the original value. In case th } ``` -When accessing an invalid index (i.e., an index greater than or equal to the array size), the JSON array is resized such that the passed index is the new maximal index. Intermediate values are filled with `#!json null`. +When accessing an invalid index (i.e., an index greater than or equal to the array size), the JSON array is resized such +that the passed index is the new maximal index. Intermediate values are filled with `#!json null`. -??? example +??? example "Filling up arrays with `#!json null` values" ```cpp j["hobbies"][0] = "running"; @@ -76,17 +79,23 @@ When accessing an invalid index (i.e., an index greater than or equal to the arr - `#!cpp std::vector::operator[]` never inserts a new element. - `#!cpp std::map::operator[]` is not available for const values. - The type `#!cpp json` wraps all JSON value types. It would be impossible to remove `operator[]` for const objects. At the same time, inserting elements for non-const objects is really convenient as it avoids awkward `insert` calls. To this end, we decided to have an inserting non-const behavior for both arrays and objects. + The type `#!cpp json` wraps all JSON value types. It would be impossible to remove + [`operator[]`](../../api/basic_json/operator%5B%5D.md) for const objects. At the same time, inserting elements for + non-const objects is really convenient as it avoids awkward `insert` calls. To this end, we decided to have an + inserting non-const behavior for both arrays and objects. !!! info - The access is unchecked. In case the passed object key does not exist or the passed array index is invalid, no exception is thrown. + The access is unchecked. In case the passed object key does not exist or the passed array index is invalid, no + exception is thrown. !!! danger - It is **undefined behavior** to access a const object with a non-existing key. - It is **undefined behavior** to access a const array with an invalid index. - - In debug mode, an **assertion** will fire in both cases. You can disable assertions by defining the preprocessor symbol `#!cpp NDEBUG` or redefine the macro [`JSON_ASSERT(x)`](../macros.md#json_assertx). + - In debug mode, an **assertion** will fire in both cases. You can disable assertions by defining the preprocessor + symbol `#!cpp NDEBUG` or redefine the macro [`JSON_ASSERT(x)`](../macros.md#json_assertx). See the documentation + on [runtime assertions](../assertions.md) for more information. !!! failure "Exceptions" diff --git a/docs/mkdocs/docs/features/iterators.md b/docs/mkdocs/docs/features/iterators.md index 46f28f189..ce627e012 100644 --- a/docs/mkdocs/docs/features/iterators.md +++ b/docs/mkdocs/docs/features/iterators.md @@ -113,7 +113,7 @@ for (auto& [key, val] : j_object.items()) ```cpp json j = {1, 2, 3, 4}; - for (auto it = j.begin(); it != j.end(); ++it) + for (auto it = j.rbegin(); it != j.rend(); ++it) { std::cout << *it << std::endl; } diff --git a/docs/mkdocs/docs/features/object_order.md b/docs/mkdocs/docs/features/object_order.md index 0768f8020..3ee16a90e 100644 --- a/docs/mkdocs/docs/features/object_order.md +++ b/docs/mkdocs/docs/features/object_order.md @@ -42,30 +42,13 @@ If you do want to preserve the **insertion order**, you can try the type [`nlohm ??? example ```cpp - #include - #include - - using ordered_json = nlohmann::ordered_json; - - int main() - { - ordered_json j; - j["one"] = 1; - j["two"] = 2; - j["three"] = 3; - - std::cout << j.dump(2) << '\n'; - } + --8<-- "examples/ordered_json.cpp" ``` Output: ```json - { - "one": 1, - "two": 2, - "three": 3 - } + --8<-- "examples/ordered_json.output" ``` Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). diff --git a/docs/mkdocs/docs/home/exceptions.md b/docs/mkdocs/docs/home/exceptions.md index 666d225bd..c9885ae6f 100644 --- a/docs/mkdocs/docs/home/exceptions.md +++ b/docs/mkdocs/docs/home/exceptions.md @@ -271,7 +271,7 @@ In a JSON Pointer, only `~0` and `~1` are valid escape sequences. A JSON Pointer array index must be a number. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.parse_error.109] parse error: array index 'one' is not a number @@ -295,19 +295,34 @@ When parsing CBOR or MessagePack, the byte vector ends before the complete value ### json.exception.parse_error.112 -Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +An unexpected byte was read in a [binary format](../features/binary_formats/index.md) or length information is invalid ([BSON](../features/binary_formats/bson.md)). -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.parse_error.112] parse error at byte 1: syntax error while parsing CBOR value: invalid byte: 0x1C ``` + ``` + [json.exception.parse_error.112] parse error at byte 1: syntax error while parsing MessagePack value: invalid byte: 0xC1 + ``` + ``` + [json.exception.parse_error.112] parse error at byte 4: syntax error while parsing BJData size: expected '#' after type information; last byte: 0x02 + ``` + ``` + [json.exception.parse_error.112] parse error at byte 4: syntax error while parsing UBJSON size: expected '#' after type information; last byte: 0x02 + ``` + ``` + [json.exception.parse_error.112] parse error at byte 10: syntax error while parsing BSON string: string length must be at least 1, is -2147483648 + ``` + ``` + [json.exception.parse_error.112] parse error at byte 15: syntax error while parsing BSON binary: byte array length cannot be negative, is -1 + ``` ### json.exception.parse_error.113 While parsing a map key, a value that is not a string has been read. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0xFF @@ -374,7 +389,7 @@ The iterators passed to constructor `basic_json(InputIT first, InputIT last)` ar In the [erase](../api/basic_json/erase.md) or insert function, the passed iterator `pos` does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.invalid_iterator.202] iterator does not fit current value @@ -538,7 +553,7 @@ To create an object from an initializer list, the initializer list must consist During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.type_error.302] type must be object, but is null @@ -551,7 +566,7 @@ During implicit or explicit value conversion, the JSON type must be compatible t To retrieve a reference to a value stored in a `basic_json` object with `get_ref`, the type of the reference must match the value type. For instance, for a JSON array, the `ReferenceType` must be `array_t &`. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object @@ -564,7 +579,7 @@ To retrieve a reference to a value stored in a `basic_json` object with `get_ref The `at()` member functions can only be executed for certain JSON types. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.type_error.304] cannot use at() with string @@ -577,7 +592,7 @@ The `at()` member functions can only be executed for certain JSON types. The `operator[]` member functions can only be executed for certain JSON types. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.type_error.305] cannot use operator[] with a string argument with array @@ -620,7 +635,7 @@ The `push_back()` and `operator+=` member functions can only be executed for cer The `insert()` member functions can only be executed for certain JSON types. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.type_error.309] cannot use insert() with array @@ -643,7 +658,7 @@ The `swap()` member functions can only be executed for certain JSON types. The `emplace()` and `emplace_back()` member functions can only be executed for certain JSON types. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.type_error.311] cannot use emplace() with number @@ -718,7 +733,7 @@ The `dump()` function only works with UTF-8 encoded strings; that is, if you ass The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) -!!! failure "Example message" +!!! failure "Example messages" Serializing `#!json null` to BSON: ``` diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index 38a8cadfa..dd4da8a0c 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -42,6 +42,7 @@ nav: - features/arbitrary_types.md - Binary Formats: - features/binary_formats/index.md + - features/binary_formats/bjdata.md - features/binary_formats/bson.md - features/binary_formats/cbor.md - features/binary_formats/messagepack.md @@ -109,6 +110,7 @@ nav: - 'exception': api/basic_json/exception.md - 'find': api/basic_json/find.md - 'flatten': api/basic_json/flatten.md + - 'from_bjdata': api/basic_json/from_bjdata.md - 'from_bson': api/basic_json/from_bson.md - 'from_cbor': api/basic_json/from_cbor.md - 'from_msgpack': api/basic_json/from_msgpack.md @@ -178,6 +180,7 @@ nav: - 'string_t': api/basic_json/string_t.md - 'swap': api/basic_json/swap.md - 'std::swap<basic_json>': api/basic_json/std_swap.md + - 'to_bjdata': api/basic_json/to_bjdata.md - 'to_bson': api/basic_json/to_bson.md - 'to_cbor': api/basic_json/to_cbor.md - 'to_msgpack': api/basic_json/to_msgpack.md diff --git a/docs/mkdocs/scripts/check_structure.py b/docs/mkdocs/scripts/check_structure.py index 92f6ff182..56de6e89f 100755 --- a/docs/mkdocs/scripts/check_structure.py +++ b/docs/mkdocs/scripts/check_structure.py @@ -47,14 +47,17 @@ def check_structure(): files = sorted(glob.glob('api/**/*.md', recursive=True)) for file in files: with open(file) as file_content: - section_idx = -1 - existing_sections = [] - in_initial_code_example = False - previous_line = None - h1sections = 0 + section_idx = -1 # the index of the current h2 section + existing_sections = [] # the list of h2 sections in the file + in_initial_code_example = False # whether we are inside the first code example block + previous_line = None # the previous read line + h1sections = 0 # the number of h1 sections in the file + last_overload = 0 # the last seen overload number in the code example + documented_overloads = {} # the overloads that have been documented in the current block + current_section = None # the name of the current section - for lineno, line in enumerate(file_content.readlines()): - line = line.strip() + for lineno, original_line in enumerate(file_content.readlines()): + line = original_line.strip() if line.startswith('# '): h1sections += 1 @@ -70,10 +73,21 @@ def check_structure(): # lines longer than 160 characters are bad (unless they are tables) if len(line) > 160 and '|' not in line: - report('whitespace/line_length', f'{file}:{lineno+1}', f'line is too long ({len(line)} vs. 160 chars)') + report('whitespace/line_length', f'{file}:{lineno+1} ({current_section})', f'line is too long ({len(line)} vs. 160 chars)') # check if sections are correct if line.startswith('## '): + # before starting a new section, check if the previous one documented all overloads + if current_section in documented_overloads and last_overload != 0: + if len(documented_overloads[current_section]) > 0 and len(documented_overloads[current_section]) != last_overload: + expected = list(range(1, last_overload+1)) + undocumented = [x for x in expected if x not in documented_overloads[current_section]] + unexpected = [x for x in documented_overloads[current_section] if x not in expected] + if len(undocumented): + report('style/numbering', f'{file}:{lineno} ({current_section})', f'undocumented overloads: {", ".join([f"({x})" for x in undocumented])}') + if len(unexpected): + report('style/numbering', f'{file}:{lineno} ({current_section})', f'unexpected overloads: {", ".join([f"({x})" for x in unexpected])}') + current_section = line.strip('## ') existing_sections.append(current_section) @@ -83,13 +97,29 @@ def check_structure(): 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: - report('structure/unknown_section', f'{file}:{lineno+1}', f'section "{current_section}" is not part of the expected sections') + if 'index.md' not in file: # index.md files may have a different structure + report('structure/unknown_section', f'{file}:{lineno+1}', f'section "{current_section}" is not part of the expected sections') + + # collect the numbered items of the current section to later check if they match the number of overloads + if last_overload != 0 and not in_initial_code_example: + if len(original_line) and original_line[0].isdigit(): + number = int(re.findall(r"^(\d+).", original_line)[0]) + if current_section not in documented_overloads: + documented_overloads[current_section] = [] + documented_overloads[current_section].append(number) # code example if line == '```cpp' and section_idx == -1: in_initial_code_example = True if in_initial_code_example and line.startswith('//'): + # check numbering of overloads + if any(map(str.isdigit, line)): + number = int(re.findall(r'\d+', line)[0]) + if number != last_overload + 1: + report('style/numbering', f'{file}:{lineno+1}', f'expected number ({number}) to be ({last_overload +1 })') + last_overload = number + if any(map(str.isdigit, line)) and '(' not in line: report('style/numbering', f'{file}:{lineno+1}', 'number should be in parentheses: {line}') @@ -98,18 +128,19 @@ def check_structure(): # consecutive blank lines are bad if line == '' and previous_line == '': - report('whitespace/blank_lines', f'{file}:{lineno}-{lineno+1}', 'consecutive blank lines') + report('whitespace/blank_lines', f'{file}:{lineno}-{lineno+1} ({current_section})', 'consecutive blank lines') # check that non-example admonitions have titles untitled_admonition = re.match(r'^(\?\?\?|!!!) ([^ ]+)$', line) if untitled_admonition and untitled_admonition.group(2) != 'example': - report('style/admonition_title', f'{file}:{lineno}', f'"{untitled_admonition.group(2)}" admonitions should have a title') + report('style/admonition_title', f'{file}:{lineno} ({current_section})', f'"{untitled_admonition.group(2)}" admonitions should have a title') previous_line = line - 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') + if 'index.md' not in file: # index.md files may have a different structure + for required_section in required_sections: + if required_section not in existing_sections: + report('structure/missing_section', f'{file}:{lineno+1}', f'required section "{required_section}" was not found') def check_examples(): diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index aed4a1a01..fb0f5fc18 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -4403,29 +4403,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return res ? result : basic_json(value_t::discarded); } - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bjdata(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true) - { - return from_bjdata(ptr, ptr + len, strict, allow_exceptions); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bjdata(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in BSON format /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ template diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index a29f7bce9..e2cd6bc2d 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -22512,29 +22512,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return res ? result : basic_json(value_t::discarded); } - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bjdata(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true) - { - return from_bjdata(ptr, ptr + len, strict, allow_exceptions); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bjdata(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in BSON format /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ template diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 75bc6f980..2f6409c57 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -76,7 +76,7 @@ endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # avoid stack overflow, see https://github.com/nlohmann/json/issues/2955 - json_test_set_test_options("test-cbor;test-msgpack;test-ubjson;test-bjdata" LINK_OPTIONS /STACK:4000000) + json_test_set_test_options("test-cbor;test-msgpack;test-ubjson;test-bjdata;test-binary_formats" LINK_OPTIONS /STACK:4000000) endif() # disable exceptions for test-disabled_exceptions diff --git a/tests/src/unit-binary_formats.cpp b/tests/src/unit-binary_formats.cpp new file mode 100644 index 000000000..05e889b0f --- /dev/null +++ b/tests/src/unit-binary_formats.cpp @@ -0,0 +1,232 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.10.5 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "doctest_compatibility.h" + +#include +using nlohmann::json; + +#include +#include + +TEST_CASE("Binary Formats" * doctest::skip()) +{ + SECTION("canada.json") + { + const auto* filename = TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json"; + json j = json::parse(std::ifstream(filename)); + + const auto json_size = j.dump().size(); + const auto bjdata_1_size = json::to_bjdata(j).size(); + const auto bjdata_2_size = json::to_bjdata(j, true).size(); + const auto bjdata_3_size = json::to_bjdata(j, true, true).size(); + const auto bson_size = json::to_bson(j).size(); + const auto cbor_size = json::to_cbor(j).size(); + const auto msgpack_size = json::to_msgpack(j).size(); + const auto ubjson_1_size = json::to_ubjson(j).size(); + const auto ubjson_2_size = json::to_ubjson(j, true).size(); + const auto ubjson_3_size = json::to_ubjson(j, true, true).size(); + + CHECK(json_size == 2090303); + CHECK(bjdata_1_size == 1112030); + CHECK(bjdata_2_size == 1224148); + CHECK(bjdata_3_size == 1224148); + CHECK(bson_size == 1794522); + CHECK(cbor_size == 1055552); + CHECK(msgpack_size == 1056145); + CHECK(ubjson_1_size == 1112030); + CHECK(ubjson_2_size == 1224148); + CHECK(ubjson_3_size == 1169069); + + CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0)); + CHECK((100.0 * double(bjdata_1_size) / double(json_size)) == Approx(53.199)); + CHECK((100.0 * double(bjdata_2_size) / double(json_size)) == Approx(58.563)); + CHECK((100.0 * double(bjdata_3_size) / double(json_size)) == Approx(58.563)); + CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(85.849)); + CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(50.497)); + CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(50.526)); + CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(53.199)); + CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(58.563)); + CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(55.928)); + } + + SECTION("twitter.json") + { + const auto* filename = TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json"; + json j = json::parse(std::ifstream(filename)); + + const auto json_size = j.dump().size(); + const auto bjdata_1_size = json::to_bjdata(j).size(); + const auto bjdata_2_size = json::to_bjdata(j, true).size(); + const auto bjdata_3_size = json::to_bjdata(j, true, true).size(); + const auto bson_size = json::to_bson(j).size(); + const auto cbor_size = json::to_cbor(j).size(); + const auto msgpack_size = json::to_msgpack(j).size(); + const auto ubjson_1_size = json::to_ubjson(j).size(); + const auto ubjson_2_size = json::to_ubjson(j, true).size(); + const auto ubjson_3_size = json::to_ubjson(j, true, true).size(); + + CHECK(json_size == 466906); + CHECK(bjdata_1_size == 425342); + CHECK(bjdata_2_size == 429970); + CHECK(bjdata_3_size == 429970); + CHECK(bson_size == 444568); + CHECK(cbor_size == 402814); + CHECK(msgpack_size == 401510); + CHECK(ubjson_1_size == 426160); + CHECK(ubjson_2_size == 430788); + CHECK(ubjson_3_size == 430798); + + CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0)); + CHECK((100.0 * double(bjdata_1_size) / double(json_size)) == Approx(91.097)); + CHECK((100.0 * double(bjdata_2_size) / double(json_size)) == Approx(92.089)); + CHECK((100.0 * double(bjdata_3_size) / double(json_size)) == Approx(92.089)); + CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(95.215)); + CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(86.273)); + CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(85.993)); + CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(91.273)); + CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(92.264)); + CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(92.266)); + } + + SECTION("citm_catalog.json") + { + const auto* filename = TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json"; + json j = json::parse(std::ifstream(filename)); + + const auto json_size = j.dump().size(); + const auto bjdata_1_size = json::to_bjdata(j).size(); + const auto bjdata_2_size = json::to_bjdata(j, true).size(); + const auto bjdata_3_size = json::to_bjdata(j, true, true).size(); + const auto bson_size = json::to_bson(j).size(); + const auto cbor_size = json::to_cbor(j).size(); + const auto msgpack_size = json::to_msgpack(j).size(); + const auto ubjson_1_size = json::to_ubjson(j).size(); + const auto ubjson_2_size = json::to_ubjson(j, true).size(); + const auto ubjson_3_size = json::to_ubjson(j, true, true).size(); + + CHECK(json_size == 500299); + CHECK(bjdata_1_size == 390781); + CHECK(bjdata_2_size == 433557); + CHECK(bjdata_3_size == 432964); + CHECK(bson_size == 479430); + CHECK(cbor_size == 342373); + CHECK(msgpack_size == 342473); + CHECK(ubjson_1_size == 391463); + CHECK(ubjson_2_size == 434239); + CHECK(ubjson_3_size == 425073); + + CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0)); + CHECK((100.0 * double(bjdata_1_size) / double(json_size)) == Approx(78.109)); + CHECK((100.0 * double(bjdata_2_size) / double(json_size)) == Approx(86.659)); + CHECK((100.0 * double(bjdata_3_size) / double(json_size)) == Approx(86.541)); + CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(95.828)); + CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(68.433)); + CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(68.453)); + CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(78.245)); + CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(86.795)); + CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(84.963)); + } + + SECTION("jeopardy.json") + { + const auto* filename = TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json"; + json j = json::parse(std::ifstream(filename)); + + const auto json_size = j.dump().size(); + const auto bjdata_1_size = json::to_bjdata(j).size(); + const auto bjdata_2_size = json::to_bjdata(j, true).size(); + const auto bjdata_3_size = json::to_bjdata(j, true, true).size(); + const auto bson_size = json::to_bson({{"", j}}).size(); // wrap array in object for BSON + const auto cbor_size = json::to_cbor(j).size(); + const auto msgpack_size = json::to_msgpack(j).size(); + const auto ubjson_1_size = json::to_ubjson(j).size(); + const auto ubjson_2_size = json::to_ubjson(j, true).size(); + const auto ubjson_3_size = json::to_ubjson(j, true, true).size(); + + CHECK(json_size == 52508728); + CHECK(bjdata_1_size == 50710965); + CHECK(bjdata_2_size == 51144830); + CHECK(bjdata_3_size == 51144830); + CHECK(bson_size == 56008520); + CHECK(cbor_size == 46187320); + CHECK(msgpack_size == 46158575); + CHECK(ubjson_1_size == 50710965); + CHECK(ubjson_2_size == 51144830); + CHECK(ubjson_3_size == 49861422); + + CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0)); + CHECK((100.0 * double(bjdata_1_size) / double(json_size)) == Approx(96.576)); + CHECK((100.0 * double(bjdata_2_size) / double(json_size)) == Approx(97.402)); + CHECK((100.0 * double(bjdata_3_size) / double(json_size)) == Approx(97.402)); + CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(106.665)); + CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(87.961)); + CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(87.906)); + CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(96.576)); + CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(97.402)); + CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(94.958)); + } + + SECTION("sample.json") + { + const auto* filename = TEST_DATA_DIRECTORY "/json_testsuite/sample.json"; + json j = json::parse(std::ifstream(filename)); + + const auto json_size = j.dump().size(); + const auto bjdata_1_size = json::to_bjdata(j).size(); + const auto bjdata_2_size = json::to_bjdata(j, true).size(); + const auto bjdata_3_size = json::to_bjdata(j, true, true).size(); + // BSON cannot process the file as it contains code point U+0000 + const auto cbor_size = json::to_cbor(j).size(); + const auto msgpack_size = json::to_msgpack(j).size(); + const auto ubjson_1_size = json::to_ubjson(j).size(); + const auto ubjson_2_size = json::to_ubjson(j, true).size(); + const auto ubjson_3_size = json::to_ubjson(j, true, true).size(); + + CHECK(json_size == 168677); + CHECK(bjdata_1_size == 148695); + CHECK(bjdata_2_size == 150569); + CHECK(bjdata_3_size == 150569); + CHECK(cbor_size == 147095); + CHECK(msgpack_size == 147017); + CHECK(ubjson_1_size == 148695); + CHECK(ubjson_2_size == 150569); + CHECK(ubjson_3_size == 150883); + + CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0)); + CHECK((100.0 * double(bjdata_1_size) / double(json_size)) == Approx(88.153)); + CHECK((100.0 * double(bjdata_2_size) / double(json_size)) == Approx(89.264)); + CHECK((100.0 * double(bjdata_3_size) / double(json_size)) == Approx(89.264)); + CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(87.205)); + CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(87.158)); + CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(88.153)); + CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(89.264)); + CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(89.450)); + } +} diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index d2fa9a9b2..0a1e6e02d 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -3404,21 +3404,6 @@ TEST_CASE("BJData roundtrips" * doctest::skip()) CHECK(j1 == j2); } - { - INFO_WITH_TEMP(filename + ": uint8_t* and size"); - // parse JSON file - std::ifstream f_json(filename); - json j1 = json::parse(f_json); - - // parse BJData file - auto packed = utils::read_binary_file(filename + ".bjdata"); - json j2; - CHECK_NOTHROW(j2 = json::from_bjdata({packed.data(), packed.size()})); - - // compare parsed JSON values - CHECK(j1 == j2); - } - { INFO_WITH_TEMP(filename + ": output to output adapters"); // parse JSON file