Compare commits

..
Author SHA1 Message Date
Niels Lohmann 52b72b5684 Improve documentation: byte layouts, release pages, See also, dark-mode images (#5906)
- Make the iterator range illustrations legible in dark mode (prefers-color-scheme
  rules inside the SVGs).
- Add a "Byte layout" section with a color-coded byte table to each binary format
  page (BJData, BON8, BSON, CBOR, MessagePack, UBJSON), and highlight the smallest
  size per file in the comparison table.
- Add "See also" sections to the overview pages that lacked one.
- Split the release notes into one page per release, grouped by minor version on
  the overview page, with an "API changes" section per release generated from the
  API pages' version histories (hooks/api_changes.py).
- Fact-check the release notes and version histories against the release tags and
  correct wrong or misleading entries (e.g., json_serializer 2.1.0, merge_patch
  3.1.0, items, count, operator[], to_bjdata, std::string_view key support).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-24 17:57:44 +02:00
156 changed files with 1466 additions and 2208 deletions

No files matched your search

@@ -30,6 +30,14 @@ struct adl_serializer {
- [**from_json**](from_json.md) - convert a JSON value to any value type - [**from_json**](from_json.md) - convert a JSON value to any value type
- [**to_json**](to_json.md) - convert any value type to a JSON value - [**to_json**](to_json.md) - convert any value type to a JSON value
## See also
- [Arbitrary type conversions](../../features/arbitrary_types.md) - how to make your types convertible
- [**get**](../basic_json/get.md) / [**get_to**](../basic_json/get_to.md) - convert a JSON value to a C++ type
- [**basic_json**](../basic_json/basic_json.md) - construct a JSON value from a C++ value
- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE**](../macros/nlohmann_define_type_intrusive.md) - generate the conversion functions for a type
- [Specializing enum conversion](../../features/enum_conversion.md)
## Version history ## Version history
- Added in version 2.1.0. - Added in version 2.1.0.
+2 -3
View File
@@ -239,9 +239,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
1. Added in version 1.0.0. 1. Added in version 1.0.0.
2. Added in version 1.0.0. 2. Added in version 1.0.0.
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as 3. Added in version 3.11.0. Support for keys convertible to `std::string_view` added in version 3.13.0, consistently
already supported by [`operator[]`](operator[].md), [`value`](value.md), [`find`](find.md), and other lookup across the lookup functions.
functions.
4. Added in version 2.0.0. Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of 4. Added in version 2.0.0. Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is not [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is not
a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones. a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones.
+1 -1
View File
@@ -63,4 +63,4 @@ Constant.
## Version history ## Version history
- Added in version 1.0.0. - Added in version 1.0.0.
- Adjusted code to return reference to binary values in version 3.8.0. - Binary values are supported since version 3.8.0.
@@ -482,15 +482,15 @@ basic_json(basic_json&& other) noexcept;
## Version history ## Version history
1. Since version 1.0.0. 1. Added in version 1.0.0.
2. Since version 1.0.0. 2. Added in version 1.0.0.
3. Since version 2.1.0. 3. Added in version 2.1.0.
4. Since version 3.2.0. Explicit for different string types if `JSON_USE_IMPLICIT_CONVERSIONS` is `0` since 4. Added in version 3.1.2. Explicit for different string types if `JSON_USE_IMPLICIT_CONVERSIONS` is `0` since
version 3.13.0. version 3.13.0.
5. Since version 1.0.0. 5. Added in version 1.0.0.
6. Since version 1.0.0. 6. Added in version 1.0.0.
7. Since version 1.0.0. Fixed in version 3.13.0 to also check the iterator range for binary values; before, a range 7. Added in version 1.0.0. Fixed in version 3.13.0 to also check the iterator range for binary values; before, a range
that did not cover the whole value (such as `(end(), end())`) was accepted and the whole binary value was copied, that did not cover the whole value (such as `(end(), end())`) was accepted and the whole binary value was copied,
unlike the other primitive types. unlike the other primitive types.
8. Since version 1.0.0. 8. Added in version 1.0.0.
9. Since version 1.0.0. 9. Added in version 1.0.0.
+2 -3
View File
@@ -141,9 +141,8 @@ Logarithmic in the size of the JSON object.
## Version history ## Version history
1. Added in version 3.11.0. 1. Added in version 3.11.0.
2. Added in version 3.6.0. Extended template `KeyType` to support comparable types in version 3.11.0. Fixed in 2. Added in version 3.6.0. Extended template `KeyType` to support comparable types in version 3.11.0. Support for keys
version 3.13.0 to consistently accept `std::string_view`-convertible keys, as already supported by convertible to `std::string_view` added in version 3.13.0, consistently across the lookup functions.
[`operator[]`](operator[].md), [`at`](at.md), [`value`](value.md), and other lookup functions.
3. Added in version 3.7.0. 3. Added in version 3.7.0.
4. Deleted overloads for integral key types added in version 3.13.0 to reject such calls at compile time instead of 4. Deleted overloads for integral key types added in version 3.13.0 to reject such calls at compile time instead of
causing undefined behavior at runtime. causing undefined behavior at runtime.
+2 -3
View File
@@ -92,8 +92,7 @@ Logarithmic in the size of the JSON object.
## Version history ## Version history
1. Added in version 3.11.0. 1. Added in version 3.11.0.
2. Added in version 1.0.0. Changed parameter `key` type to `KeyType&&` in version 3.11.0. Fixed in version 3.13.0 to 2. Added in version 1.0.0. Changed to support comparable key types in version 3.11.0. Support for keys convertible to
consistently accept `std::string_view`-convertible keys, as already supported by [`operator[]`](operator[].md), `std::string_view` added in version 3.13.0, consistently across the lookup functions.
[`at`](at.md), [`value`](value.md), and other lookup functions.
3. Deleted overload for integral key types added in version 3.13.0 to reject such calls at compile time instead of 3. Deleted overload for integral key types added in version 3.13.0 to reject such calls at compile time instead of
causing undefined behavior at runtime. causing undefined behavior at runtime.
+1 -1
View File
@@ -69,6 +69,6 @@ Logarithmic in the size of the container, O(log(`size()`)).
## Version history ## Version history
- Since version 2.0.8. - Added in version 2.0.8.
- Fixed in version 3.13.0: for [`ordered_json`](../ordered_json.md), the value could previously only be passed as an - Fixed in version 3.13.0: for [`ordered_json`](../ordered_json.md), the value could previously only be passed as an
rvalue; it can now also be passed as an lvalue or a `#!cpp const` lvalue, matching the behavior of `json`. rvalue; it can now also be passed as an lvalue or a `#!cpp const` lvalue, matching the behavior of `json`.
@@ -67,5 +67,5 @@ Amortized constant.
## Version history ## Version history
- Since version 2.0.8. - Added in version 2.0.8.
- Returns reference since 3.7.0. - Returns reference since 3.7.0.
+2 -3
View File
@@ -213,7 +213,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
1. Added in version 1.0.0. Added support for binary types in version 3.8.0. 1. Added in version 1.0.0. Added support for binary types in version 3.8.0.
2. Added in version 1.0.0. Added support for binary types in version 3.8.0. 2. Added in version 1.0.0. Added support for binary types in version 3.8.0.
3. Added in version 1.0.0. 3. Added in version 1.0.0.
4. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as 4. Added in version 3.11.0. Support for keys convertible to `std::string_view` added in version 3.13.0, consistently
already supported by [`operator[]`](operator[].md), [`at`](at.md), [`value`](value.md), and other lookup across the lookup functions.
functions.
5. Added in version 1.0.0. 5. Added in version 1.0.0.
+1 -1
View File
@@ -84,4 +84,4 @@ constructor.
## Version history ## Version history
- Since version 3.0.0. - Added in version 3.0.0.
+2 -3
View File
@@ -99,8 +99,7 @@ Logarithmic in the size of the JSON object.
## Version history ## Version history
1. Added in version 3.11.0. 1. Added in version 3.11.0.
2. Added in version 1.0.0. Changed to support comparable types in version 3.11.0. Fixed in version 3.13.0 to 2. Added in version 1.0.0. Changed to support comparable types in version 3.11.0. Support for keys convertible to
consistently accept `std::string_view`-convertible keys, as already supported by [`operator[]`](operator[].md), `std::string_view` added in version 3.13.0, consistently across the lookup functions.
[`at`](at.md), [`value`](value.md), and other lookup functions.
3. Deleted overloads for integral key types added in version 3.13.0 to reject such calls at compile time instead of 3. Deleted overloads for integral key types added in version 3.13.0 to reject such calls at compile time instead of
causing undefined behavior at runtime. causing undefined behavior at runtime.
+1 -1
View File
@@ -57,4 +57,4 @@ Constant.
## Version history ## Version history
- Added in version 1.0.0. - Added in version 1.0.0.
- Adjusted code to return reference to binary values in version 3.8.0. - Binary values are supported since version 3.8.0.
+3 -3
View File
@@ -188,6 +188,6 @@ overload (3).
## Version history ## Version history
1. Since version 2.1.0. 1. Added in version 2.1.0.
2. Since version 2.1.0. Extended to work with other specializations of `basic_json` in version 3.2.0. 2. Added in version 2.1.0. Extended to work with other specializations of `basic_json` in version 3.1.2.
3. Since version 1.0.0. 3. Added in version 1.0.0.
+1 -1
View File
@@ -76,5 +76,5 @@ Depends on the `json_serializer<ValueType>::from_json()` implementation.
## Version history ## Version history
- Since version 3.3.0. - Added in version 3.3.0.
- Added a `static_assert` with a clear message for `const` arguments in version 3.13.0. - Added a `static_assert` with a clear message for `const` arguments in version 3.13.0.
@@ -75,4 +75,4 @@ classDiagram
## Version history ## Version history
- Since version 3.0.0. - Added in version 3.0.0.
+2 -2
View File
@@ -104,8 +104,8 @@ When iterating over an array, `key()` will return the index of the element as st
## Version history ## Version history
- Added `iterator_wrapper` in version 3.0.0. - Added in version 3.1.0 as the replacement of the static function `iterator_wrapper`, which was available since
- Added `items` and deprecated `iterator_wrapper` in version 3.1.0. version 1.0.0 and is deprecated since version 3.1.0.
- Added structured binding support in version 3.5.0. - Added structured binding support in version 3.5.0.
!!! warning "Deprecation" !!! warning "Deprecation"
@@ -51,4 +51,4 @@ deserializes. See [Template Parameter Requirements](../../features/types/templat
## Version history ## Version history
- Since version 2.0.0. - Added in version 2.1.0.
@@ -71,6 +71,6 @@ returned by `#!cpp (*this)[key]`); it is read as it was when `merge_patch()` was
## Version history ## Version history
- Added in version 3.0.0. - Added in version 3.1.0.
- Fixed use of freed or relocated memory when `apply_patch` is `#!cpp *this` or refers to a value contained in - Fixed use of freed or relocated memory when `apply_patch` is `#!cpp *this` or refers to a value contained in
`#!cpp *this`, in version 3.13.0. `#!cpp *this`, in version 3.13.0.
@@ -128,6 +128,6 @@ interpreted as `object_t::value_type` or `std::initializer_list<basic_json>`, se
## Version history ## Version history
1. Since version 1.0.0. 1. Added in version 1.0.0.
2. Since version 1.0.0. 2. Added in version 1.0.0.
3. Since version 2.0.0. 3. Added in version 2.0.0.
@@ -284,10 +284,10 @@ Strong exception safety: if an exception occurs, the original value stays intact
1. Added in version 1.0.0. Fixed in version 3.13.0 to throw `#!cpp std::length_error` instead of emptying the array and 1. Added in version 1.0.0. Fixed in version 3.13.0 to throw `#!cpp std::length_error` instead of emptying the array and
accessing it out of bounds when `idx` equals the maximum value of `size_type`. A missing index in the const version accessing it out of bounds when `idx` equals the maximum value of `size_type`. A missing index in the const version
is guarded by a runtime assertion since version 3.13.0. is guarded by a runtime assertion since version 3.13.0.
2. Added in version 1.0.0. Added overloads for `T* key` in version 1.1.0. Removed overloads for `T* key` (replaced by 3) 2. Added in version 1.0.0. Added overloads for `T* key` in version 1.1.0. The `T* key` overloads forward to
in version 3.11.0. overload 3 since version 3.11.0.
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as 3. Added in version 3.11.0. Support for keys convertible to `std::string_view` added in version 3.13.0, consistently
already supported by [`at`](at.md), [`value`](value.md), [`find`](find.md), and other lookup functions. across the lookup functions.
4. Added in version 2.0.0. A missing array index in the const version is guarded by a runtime assertion since 4. Added in version 2.0.0. A missing array index in the const version is guarded by a runtime assertion since
version 3.13.0. Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of version 3.13.0. Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is not [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is not
@@ -89,6 +89,6 @@ Linear in the size of the JSON value.
## Version history ## Version history
- Since version 1.0.0. - Added in version 1.0.0.
- Macros `JSON_EXPLICIT`/[`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) added - Macros `JSON_EXPLICIT`/[`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) added
in version 3.9.0. in version 3.9.0.
@@ -75,4 +75,4 @@ classDiagram
## Version history ## Version history
- Since version 3.0.0. - Added in version 3.0.0.
@@ -76,4 +76,4 @@ classDiagram
## Version history ## Version history
- Since version 3.0.0. - Added in version 3.0.0.
@@ -84,4 +84,4 @@ or the end of file. This also holds true when reading a byte vector for binary f
## Version history ## Version history
- Since version 3.0.0. - Added in version 3.0.0.
+3 -3
View File
@@ -125,6 +125,6 @@ throws.
## Version history ## Version history
1. Since version 1.0.0. 1. Added in version 1.0.0.
2. Since version 1.0.0. 2. Added in version 1.0.0.
3. Since version 2.0.0. 3. Added in version 2.0.0.
+7 -7
View File
@@ -182,10 +182,10 @@ Constant.
## Version history ## Version history
1. Since version 1.0.0. Exchanges the `json_base_class_t` subobject along with the value since version 3.13.0. 1. Added in version 1.0.0. Exchanges the `json_base_class_t` subobject along with the value since version 3.13.0.
2. Since version 1.0.0. Exchanges the `json_base_class_t` subobject along with the value since version 3.13.0. 2. Added in version 1.0.0. Exchanges the `json_base_class_t` subobject along with the value since version 3.13.0.
3. Since version 1.0.0. 3. Added in version 1.0.0.
4. Since version 1.0.0. 4. Added in version 1.0.0.
5. Since version 1.0.0. 5. Added in version 1.0.0.
6. Since version 3.8.0. 6. Added in version 3.8.0.
7. Since version 3.8.0. 7. Added in version 3.8.0.
@@ -124,5 +124,3 @@ Linear in the size of the JSON value `j`.
[`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316`. [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316`.
- Throws `type_error.321` for a discarded value since version 3.13.0; previously, a discarded value nested in an - Throws `type_error.321` for a discarded value since version 3.13.0; previously, a discarded value nested in an
array or object was silently skipped, producing invalid BJData. array or object was silently skipped, producing invalid BJData.
- Writes unsigned integers wider than 64 bits as high-precision numbers since version 3.13.0; previously, they were
silently truncated to 64 bits.
@@ -76,4 +76,4 @@ classDiagram
## Version history ## Version history
- Since version 3.0.0. - Added in version 3.0.0.
+3 -6
View File
@@ -231,11 +231,8 @@ changes to any JSON value.
1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version 1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version
3.11.0. Deleted overload for integral key types added in version 3.13.0 to reject such calls at compile time 3.11.0. Deleted overload for integral key types added in version 3.13.0 to reject such calls at compile time
instead of causing undefined behavior at runtime. instead of causing undefined behavior at runtime.
2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2. Fixed in version 3.13.0 2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2. Support for keys
to consistently accept `std::string_view`-convertible keys, as already supported by convertible to `std::string_view` added in version 3.13.0, consistently across the lookup functions.
[`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), and other lookup functions. 3. Added in version 2.0.2. Extended to work with arrays in version 3.13.0. Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109)
3. Added in version 2.0.2. Extended to work with arrays in version 3.13.0, including fixing an issue where resolving
`ptr` through an array unexpectedly threw `out_of_range` instead of returning the resolved element (or
`default_value`, as documented). Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109)
instead of returning `default_value` for a one-character array index that is not a digit (e.g., `/x`) in version instead of returning `default_value` for a one-character array index that is not a digit (e.g., `/x`) in version
3.13.0, as it already did for longer ones. 3.13.0, as it already did for longer ones.
@@ -115,6 +115,13 @@ points apply to every edit:
[`source_offset()`](../basic_json_view/source_offset.md) of a value introduced by an edit is [`source_offset()`](../basic_json_view/source_offset.md) of a value introduced by an edit is
`#!cpp static_cast<std::size_t>(-1)`, the same value it reports for a decoded string. `#!cpp static_cast<std::size_t>(-1)`, the same value it reports for a decoded string.
## See also
- [Zero-copy JSON views](../../features/json_view.md) - guide to documents and views
- [**basic_json_view**](../basic_json_view/index.md) - the non-owning handle to a value in a document
- [**json_document**](../json_document.md) and [**json_editable_document**](../json_editable_document.md) - the default specializations
- [**materialize**](../basic_json_view/materialize.md) - build a `basic_json` value from a view
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.13.0.
@@ -143,6 +143,13 @@ still refers to it -- including ones taken before the change -- reads the new va
- [**source_offset**](source_offset.md) - byte offset of this value in the document's source text - [**source_offset**](source_offset.md) - byte offset of this value in the document's source text
## See also
- [Zero-copy JSON views](../../features/json_view.md) - guide to documents and views
- [**basic_json_document**](../basic_json_document/index.md) - the document that owns the parsed data
- [**json_view**](../json_view.md) and [**json_editable_view**](../json_editable_view.md) - the default specializations
- [**materialize**](materialize.md) - build a `basic_json` value from a view
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.13.0.
@@ -51,4 +51,4 @@ byte_container_with_subtype(container_type&& container, subtype_type subtype);
## Version history ## Version history
Since version 3.8.0. Added in version 3.8.0.
@@ -39,4 +39,4 @@ Constant.
## Version history ## Version history
Since version 3.8.0. Added in version 3.8.0.
@@ -42,4 +42,4 @@ Constant.
## Version history ## Version history
Since version 3.8.0. Added in version 3.8.0.
@@ -29,6 +29,14 @@ specific naming scheme in order to override the binary type.
- [**has_subtype**](has_subtype.md) - return whether the value has a subtype - [**has_subtype**](has_subtype.md) - return whether the value has a subtype
- [**clear_subtype**](clear_subtype.md) - clears the binary subtype - [**clear_subtype**](clear_subtype.md) - clears the binary subtype
## See also
- [Binary values](../../features/binary_values.md) - how binary values and subtypes are handled
- [**binary**](../basic_json/binary.md) - create a binary array value
- [**get_binary**](../basic_json/get_binary.md) - get a reference to the stored binary value
- [**binary_t**](../basic_json/binary_t.md) - type for binary arrays
- [Binary formats](../../features/binary_formats/index.md) - formats that can store binary values
## Version history ## Version history
- Added in version 3.8.0. - Added in version 3.8.0.
@@ -44,4 +44,4 @@ Constant.
## Version history ## Version history
Since version 3.8.0. Added in version 3.8.0.
+1 -1
View File
@@ -30,4 +30,4 @@ types.
## Version history ## Version history
Since version 1.0.0. Added in version 1.0.0.
+1 -1
View File
@@ -32,4 +32,4 @@ specialization.
## Version history ## Version history
Since version 3.13.0. Added in version 3.13.0.
@@ -40,4 +40,4 @@ parsing, without ever rewriting the source text -- see [Edits](basic_json_docume
## Version history ## Version history
Since version 3.13.0. Added in version 3.13.0.
+1 -1
View File
@@ -38,4 +38,4 @@ still referring to it seeing the change, see [Edits](basic_json_document/index.m
## Version history ## Version history
Since version 3.13.0. Added in version 3.13.0.
@@ -51,5 +51,5 @@ operator string_t() const
## Version history ## Version history
- Since version 2.0.0. - Added in version 2.0.0.
- Changed type to `string_t` and deprecated in version 3.11.0. - Changed type to `string_t` and deprecated in version 3.11.0.
@@ -49,5 +49,5 @@ ptr == json_pointer(ptr.to_string());
## Version history ## Version history
- Since version 2.0.0. - Added in version 2.0.0.
- Changed return type to `string_t` in version 3.11.0. - Changed return type to `string_t` in version 3.11.0.
+7
View File
@@ -59,6 +59,13 @@ leading `-` sign.
- [**start_object**](start_object.md) (_virtual_) - the beginning of an object was read - [**start_object**](start_object.md) (_virtual_) - the beginning of an object was read
- [**string**](string.md) (_virtual_) - a string value was read - [**string**](string.md) (_virtual_) - a string value was read
## See also
- [SAX interface](../../features/parsing/sax_interface.md) - guide to event-based parsing
- [**sax_parse**](../basic_json/sax_parse.md) - generate SAX events from an input
- [**parse**](../basic_json/parse.md) - DOM parsing, with optional [parser callbacks](../../features/parsing/parser_callbacks.md)
- [Parse exceptions](../../features/parsing/parse_exceptions.md)
## Version history ## Version history
- Added in version 3.2.0. - Added in version 3.2.0.
+1 -1
View File
@@ -31,4 +31,4 @@ This type is a [`basic_json_view`](basic_json_view/index.md) of a value of a [`j
## Version history ## Version history
Since version 3.13.0. Added in version 3.13.0.
+10 -1
View File
@@ -137,4 +137,13 @@ header. See also the [macro overview page](../../features/macros.md).
- [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize - [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize/deserialize
a derived class; uses default values; uses custom names a derived class; uses default values; uses custom names
- [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize a derived - [**NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES**](nlohmann_define_type_with_names.md) - serialize a derived
class; uses custom names class; uses custom names
## See also
- [Macros](../../features/macros.md) - guide to the supported macros
- [Runtime assertions](../../features/assertions.md)
- [Arbitrary type conversions](../../features/arbitrary_types.md) - using the `NLOHMANN_DEFINE_TYPE_*` macros
- [Enum conversion](../../features/enum_conversion.md) - using `NLOHMANN_JSON_SERIALIZE_ENUM`
- [The `nlohmann` namespace](../../features/namespace.md)
- [CMake integration](../../integration/cmake.md) - setting macros from the build system
+1 -1
View File
@@ -42,4 +42,4 @@ parsing an object of `n` keys costs O(n²) rather than O(n log n). See
## Version history ## Version history
Since version 3.9.0. Added in version 3.9.0.
@@ -35,4 +35,4 @@ of object keys, instead of sorting them like [`json_document`](json_document.md)
## Version history ## Version history
Since version 3.13.0. Added in version 3.13.0.
@@ -44,4 +44,4 @@ members [`set`](basic_json_document/set.md) added -- instead of sorting them lik
## Version history ## Version history
Since version 3.13.0. Added in version 3.13.0.
@@ -37,4 +37,4 @@ This type is a [`basic_json_view`](basic_json_view/index.md) of a value of an
## Version history ## Version history
Since version 3.13.0. Added in version 3.13.0.
+1 -1
View File
@@ -32,4 +32,4 @@ This type is a [`basic_json_view`](basic_json_view/index.md) of a value of an
## Version history ## Version history
Since version 3.13.0. Added in version 3.13.0.
+1 -1
View File
@@ -58,7 +58,7 @@ particular, a 3.x release does not:
- remove or rename a documented macro, CMake option, CMake target, or header, or change what a documented macro does. - remove or rename a documented macro, CMake option, CMake target, or header, or change what a documented macro does.
Exceptions to these rules, for instance when fixing a bug requires changing the exception a function throws, are Exceptions to these rules, for instance when fixing a bug requires changing the exception a function throws, are
documented in the [release notes](../home/releases.md). documented in the [release notes](../home/releases/index.md).
The following are **not** part of the public API and may change in any release, including patch releases: The following are **not** part of the public API and may change in any release, including patch releases:
+29
View File
@@ -18,3 +18,32 @@
white-space: nowrap; white-space: nowrap;
cursor: help; cursor: help;
} }
/* byte layout tables of the binary formats */
.md-typeset .byte-layout td code {
white-space: pre-wrap;
}
.md-typeset .bl {
display: inline-block;
padding: 0 .25em;
border-radius: .2em;
font-family: var(--md-code-font-family);
font-size: .85em;
white-space: nowrap;
}
.md-typeset .bl-t {
background-color: rgba(66, 133, 244, .25);
box-shadow: inset 0 -.12em 0 rgba(66, 133, 244, .8);
}
.md-typeset .bl-l {
background-color: rgba(251, 140, 0, .25);
box-shadow: inset 0 -.12em 0 rgba(251, 140, 0, .8);
}
.md-typeset .bl-d {
background-color: rgba(67, 160, 71, .25);
box-shadow: inset 0 -.12em 0 rgba(67, 160, 71, .8);
}
@@ -1,42 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
json j = json::parse(R"({"name": "Mary", "age": 42})");
// look up the key, then test the type: neither step throws
for (const char* key : {"name", "age", "city"})
{
const auto it = j.find(key);
if (it == j.end())
{
std::cout << key << ": missing\n";
}
else if (it->is_string())
{
std::cout << key << ": string \"" << it->get_ref<const std::string&>() << "\"\n";
}
else
{
std::cout << key << ": not a string, but " << it->type_name() << '\n';
}
}
// get_ptr returns a null pointer if the value has another type
const std::string* name = j["name"].get_ptr<const std::string*>();
const std::string* age = j["age"].get_ptr<const std::string*>();
std::cout << "get_ptr<string*>: name = " << (name != nullptr) << ", age = " << (age != nullptr) << '\n';
// value() is NOT exception-free: it throws if the key exists with a different type
try
{
std::cout << j.value("name", 0) << '\n';
}
catch (const json::type_error& e)
{
std::cout << e.what() << '\n';
}
}
@@ -1,5 +0,0 @@
name: string "Mary"
age: not a string, but number
city: missing
get_ptr<string*>: name = 1, age = 0
[json.exception.type_error.302] type must be number, but is string
@@ -1,46 +0,0 @@
#include <iostream>
#include <optional>
#include <string>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
struct person
{
std::string name;
int age;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, age)
// Compile this function with exceptions enabled and call it from code that does not use them.
std::optional<person> to_person(const json& j)
{
try
{
return j.get<person>();
}
catch (const json::exception&)
{
return std::nullopt;
}
}
int main()
{
const json good = {{"name", "Mary"}, {"age", 42}};
const json bad = {{"name", "Mary"}, {"age", "forty-two"}};
const json incomplete = {{"name", "Mary"}};
for (const json& j : {good, bad, incomplete})
{
if (const auto p = to_person(j))
{
std::cout << "person: " << p->name << ", " << p->age << '\n';
}
else
{
std::cout << "not a person: " << j << '\n';
}
}
}
@@ -1,3 +0,0 @@
person: Mary, 42
not a person: {"age":"forty-two","name":"Mary"}
not a person: {"name":"Mary"}
@@ -1,28 +0,0 @@
#include <cstdint>
#include <iostream>
#include <vector>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
// None of the calls below throws, so this example also works with -fno-exceptions.
int main()
{
const std::string invalid = R"({"name": "Mary", "age": )";
// parse() with allow_exceptions = false returns a discarded value
json j = json::parse(invalid, nullptr, false);
std::cout << std::boolalpha << "parse: discarded = " << j.is_discarded() << '\n';
// accept() only tells whether the input is valid JSON
std::cout << "accept: " << json::accept(invalid) << '\n';
// the binary formats have the same parameter
const std::vector<std::uint8_t> truncated_cbor = {0x83, 0x01};
json c = json::from_cbor(truncated_cbor, true, false);
std::cout << "from_cbor: discarded = " << c.is_discarded() << '\n';
// valid input is parsed as usual
json valid = json::parse(R"({"name": "Mary"})", nullptr, false);
std::cout << "valid input: " << valid << '\n';
}
@@ -1,4 +0,0 @@
parse: discarded = true
accept: false
from_cbor: discarded = true
valid input: {"name":"Mary"}
@@ -1,42 +0,0 @@
#include <iostream>
#include <utility>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
// line and column (both starting at 1) of a byte index in a text
std::pair<std::size_t, std::size_t> line_column(const std::string& input, std::size_t byte)
{
std::size_t line = 1;
std::size_t column = 1;
for (std::size_t i = 0; i + 1 < byte && i < input.size(); ++i)
{
if (input[i] == '\n')
{
++line;
column = 1;
}
else
{
++column;
}
}
return {line, column};
}
int main()
{
const std::string input = "{\n \"a\": 1,\n \"b\": ]\n}";
try
{
const json j = json::parse(input);
std::cout << j << '\n';
}
catch (const json::parse_error& e)
{
const auto position = line_column(input, e.byte);
std::cout << e.what() << '\n';
std::cout << "byte " << e.byte << " = line " << position.first << ", column " << position.second << '\n';
}
}
@@ -1,2 +0,0 @@
[json.exception.parse_error.101] parse error at line 3, column 8: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
byte 20 = line 3, column 8
@@ -1,46 +0,0 @@
#define JSON_DIAGNOSTIC_POSITIONS 1
#include <iostream>
#include <utility>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
// line and column (both starting at 1) of a byte index in a text
std::pair<std::size_t, std::size_t> line_column(const std::string& input, std::size_t byte)
{
std::size_t line = 1;
std::size_t column = 1;
for (std::size_t i = 0; i + 1 < byte && i < input.size(); ++i)
{
if (input[i] == '\n')
{
++line;
column = 1;
}
else
{
++column;
}
}
return {line, column};
}
int main()
{
const std::string input = "{\n \"name\": \"Mary\",\n \"age\": \"forty-two\"\n}";
const json j = json::parse(input); // the input is valid JSON ...
try
{
const int age = j["age"]; // ... but the value has the wrong type
std::cout << age << '\n';
}
catch (const json::exception& e)
{
std::cout << e.what() << '\n';
// start_pos() is a 0-based index into the input; the helper expects a 1-based byte index
const auto position = line_column(input, j["age"].start_pos() + 1);
std::cout << "the value starts at line " << position.first << ", column " << position.second << '\n';
}
}
@@ -1,2 +0,0 @@
[json.exception.type_error.302] (bytes 29-40) type must be number, but is string
the value starts at line 3, column 10
@@ -1,46 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
std::string buffer;
// call for every chunk; returns true and sets `value` once the buffer holds one complete JSON value
bool push(const std::string& chunk, json& value)
{
buffer += chunk;
try
{
value = json::parse(buffer);
buffer.clear();
return true;
}
catch (const json::parse_error& e)
{
if (e.byte == buffer.size() + 1)
{
return false; // the input ends prematurely: wait for more data
}
throw; // a real syntax error
}
}
int main()
{
json value;
for (const std::string chunk : {"{\"na", "me\": \"Ma", "ry\", \"l", "ist\": [1, 2", ", 3]}"})
{
std::cout << "chunk " << chunk << " -> " << (push(chunk, value) ? "complete" : "incomplete") << '\n';
}
std::cout << value << '\n';
// a syntax error in the middle is not mistaken for missing data
try
{
push("[1, ]", value);
}
catch (const json::parse_error& e)
{
std::cout << e.what() << '\n';
}
}
@@ -1,7 +0,0 @@
chunk {"na -> incomplete
chunk me": "Ma -> incomplete
chunk ry", "l -> incomplete
chunk ist": [1, 2 -> incomplete
chunk , 3]} -> complete
{"list":[1,2,3],"name":"Mary"}
[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
@@ -1,23 +0,0 @@
#include <iostream>
#include <sstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// a CBOR value followed by other data
const std::vector<std::uint8_t> cbor = json::to_cbor(json{1, 2, 3});
std::string data(cbor.begin(), cbor.end());
data += "TRAILING";
std::istringstream input(data);
json j = json::from_cbor(input, false); // strict = false: stop after the first value
std::cout << "value: " << j << '\n';
std::cout << "bytes used: " << input.tellg() << '\n';
std::string rest;
input >> rest;
std::cout << "remaining input: " << rest << '\n';
}
@@ -1,3 +0,0 @@
value: [1,2,3]
bytes used: 4
remaining input: TRAILING
@@ -1,18 +0,0 @@
#include <iostream>
#include <sstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
std::istringstream input(R"({"a":1} [2,3] 4 "s")");
// check for the end of the stream before each read, because a read at the end throws
json j;
while (input >> std::ws && input.peek() != std::char_traits<char>::eof())
{
input >> j;
std::cout << j << '\n';
}
}
@@ -1,4 +0,0 @@
{"a":1}
[2,3]
4
"s"
@@ -1,27 +0,0 @@
#include <iostream>
#include <sstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
void handle(const json& record)
{
std::cout << "handling " << record << '\n';
}
int main()
{
std::istringstream file(R"([{"id": 1}, {"id": 2}, {"id": 3}])");
json result = json::parse(file, [](int depth, json::parse_event_t event, json & record)
{
if (depth == 1 && event == json::parse_event_t::object_end)
{
handle(record);
return false; // discard the record
}
return true;
});
std::cout << "result: " << result << '\n';
}
@@ -1,4 +0,0 @@
handling {"id":1}
handling {"id":2}
handling {"id":3}
result: []
@@ -1,81 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
struct find_id : nlohmann::json_sax<json>
{
bool next_is_id = false;
json::number_unsigned_t id = 0;
bool key(std::string& name) override
{
next_is_id = (name == "id");
return true;
}
bool number_unsigned(json::number_unsigned_t value) override
{
if (next_is_id)
{
id = value;
return false; // found: stop parsing
}
return true;
}
bool null() override
{
return true;
}
bool boolean(bool /*val*/) override
{
return true;
}
bool number_integer(json::number_integer_t /*val*/) override
{
return true;
}
bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override
{
return true;
}
bool string(std::string& /*val*/) override
{
return true;
}
bool binary(json::binary_t& /*val*/) override
{
return true;
}
bool start_object(std::size_t /*elements*/) override
{
return true;
}
bool end_object() override
{
return true;
}
bool start_array(std::size_t /*elements*/) override
{
return true;
}
bool end_array() override
{
return true;
}
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override
{
return false;
}
};
int main()
{
find_id handler;
const bool completed = json::sax_parse(R"({"x": [1, 2, 3], "id": 42, "rest": [4, 5, 6]})", &handler);
std::cout << std::boolalpha;
std::cout << "parse completed: " << completed << '\n';
std::cout << "id: " << handler.id << '\n';
}
@@ -1,2 +0,0 @@
parse completed: false
id: 42
@@ -1,56 +0,0 @@
#include <chrono>
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
namespace nlohmann
{
template <typename Rep, typename Period>
struct adl_serializer<std::chrono::duration<Rep, Period>>
{
static void to_json(json& j, const std::chrono::duration<Rep, Period>& d)
{
j = d.count();
}
static void from_json(const json& j, std::chrono::duration<Rep, Period>& d)
{
d = std::chrono::duration<Rep, Period>(j.get<Rep>());
}
};
template <typename Duration>
struct adl_serializer<std::chrono::time_point<std::chrono::system_clock, Duration>>
{
static void to_json(json& j, const std::chrono::time_point<std::chrono::system_clock, Duration>& t)
{
j = t.time_since_epoch();
}
static void from_json(const json& j, std::chrono::time_point<std::chrono::system_clock, Duration>& t)
{
t = std::chrono::time_point<std::chrono::system_clock, Duration>(j.get<Duration>());
}
};
} // namespace nlohmann
int main()
{
using namespace std::chrono;
std::cout << std::boolalpha;
// the unit is not part of the JSON value
const json timeout = milliseconds(1500);
std::cout << "duration: " << timeout << '\n';
std::cout << "as milliseconds: " << timeout.get<milliseconds>().count() << '\n';
// a system_clock time point is the time since the Unix epoch
const time_point<system_clock, milliseconds> t(milliseconds(1700000000123));
const json stamp = t;
std::cout << "time point: " << stamp << '\n';
const auto back = stamp.get<time_point<system_clock, milliseconds>>();
std::cout << "round trip: " << (back == t) << '\n';
}
@@ -1,4 +0,0 @@
duration: 1500
as milliseconds: 1500
time point: 1700000000123
round trip: true
@@ -1,99 +0,0 @@
#include <iostream>
#include <memory>
#include <stdexcept>
#include <vector>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
struct shape
{
virtual ~shape() = default;
virtual json serialize() const = 0;
};
struct circle : shape
{
double radius;
explicit circle(double r) : radius(r) {}
json serialize() const override
{
return {{"type", "circle"}, {"radius", radius}};
}
};
struct rectangle : shape
{
double width;
double height;
rectangle(double w, double h) : width(w), height(h) {}
json serialize() const override
{
return {{"type", "rectangle"}, {"width", width}, {"height", height}};
}
};
namespace nlohmann
{
template <>
struct adl_serializer<std::unique_ptr<shape>>
{
static void to_json(json& j, const std::unique_ptr<shape>& p)
{
j = p ? p->serialize() : json(nullptr);
}
static void from_json(const json& j, std::unique_ptr<shape>& p)
{
if (j.is_null())
{
p.reset();
return;
}
const auto& type = j.at("type").get_ref<const std::string&>();
if (type == "circle")
{
p = std::make_unique<circle>(j.at("radius").get<double>());
}
else if (type == "rectangle")
{
p = std::make_unique<rectangle>(j.at("width").get<double>(), j.at("height").get<double>());
}
else
{
throw std::invalid_argument("unknown shape type: " + type);
}
}
};
} // namespace nlohmann
int main()
{
std::vector<std::unique_ptr<shape>> shapes;
shapes.push_back(std::make_unique<circle>(1.5));
shapes.push_back(std::make_unique<rectangle>(2, 3));
const json j = shapes;
std::cout << j << '\n';
// reading creates objects of the derived types
const auto back = j.get<std::vector<std::unique_ptr<shape>>>();
std::cout << std::boolalpha;
std::cout << "first is a circle: " << (dynamic_cast<circle*>(back[0].get()) != nullptr) << '\n';
std::cout << "second is a rectangle: " << (dynamic_cast<rectangle*>(back[1].get()) != nullptr) << '\n';
// an unknown type tag is reported
try
{
json{{"type", "star"}}.get<std::unique_ptr<shape>>();
}
catch (const std::invalid_argument& e)
{
std::cout << e.what() << '\n';
}
}
@@ -1,4 +0,0 @@
[{"radius":1.5,"type":"circle"},{"height":3.0,"type":"rectangle","width":2.0}]
first is a circle: true
second is a rectangle: true
unknown shape type: star
@@ -1,90 +0,0 @@
#include <iostream>
#include <memory>
#include <vector>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
namespace nlohmann
{
template <typename T>
struct adl_serializer<std::shared_ptr<T>>
{
static void to_json(json& j, const std::shared_ptr<T>& p)
{
if (p)
{
j = *p;
}
else
{
j = nullptr;
}
}
static void from_json(const json& j, std::shared_ptr<T>& p)
{
if (j.is_null())
{
p = nullptr;
}
else
{
p = std::make_shared<T>(j.get<typename std::remove_const<T>::type>());
}
}
};
template <typename T>
struct adl_serializer<std::unique_ptr<T>>
{
static void to_json(json& j, const std::unique_ptr<T>& p)
{
if (p)
{
j = *p;
}
else
{
j = nullptr;
}
}
static void from_json(const json& j, std::unique_ptr<T>& p)
{
if (j.is_null())
{
p = nullptr;
}
else
{
p = std::make_unique<T>(j.get<T>());
}
}
};
} // namespace nlohmann
struct point
{
int x;
int y;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(point, x, y)
int main()
{
// an empty pointer is written as null
const std::vector<std::shared_ptr<point>> points = {std::make_shared<point>(point{1, 2}), nullptr};
const json j = points;
std::cout << j << '\n';
// reading allocates new objects
const auto back = j.get<std::vector<std::shared_ptr<point>>>();
std::cout << back[0]->x << ", " << back[0]->y << ", " << (back[1] == nullptr) << '\n';
// pointers to const and unique_ptr work as well
const auto const_ptr = j[0].get<std::shared_ptr<const point>>();
const auto unique = j[0].get<std::unique_ptr<point>>();
std::cout << const_ptr->y << ", " << unique->x << '\n';
}
@@ -1,3 +0,0 @@
[{"x":1,"y":2},null]
1, 2, 1
2, 1
@@ -1,63 +0,0 @@
#include <iostream>
#include <stdexcept>
#include <variant>
#include <vector>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
namespace geo
{
struct circ
{
double radius;
};
struct rect
{
double width;
double height;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(circ, radius)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(rect, width, height)
using figure = std::variant<circ, rect>;
void to_json(json& j, const figure& f)
{
std::visit([&j](const auto & alternative)
{
j = alternative;
}, f);
j["type"] = std::holds_alternative<circ>(f) ? "circ" : "rect";
}
void from_json(const json& j, figure& f)
{
const auto& type = j.at("type").get_ref<const std::string&>();
if (type == "circ")
{
f = j.get<circ>();
}
else if (type == "rect")
{
f = j.get<rect>();
}
else
{
throw std::invalid_argument("unknown figure type: " + type);
}
}
} // namespace geo
int main()
{
const std::vector<geo::figure> figures = {geo::circ{2}, geo::rect{3, 4}};
const json j = figures;
std::cout << j << '\n';
const auto back = j.get<std::vector<geo::figure>>();
std::cout << "alternatives read back: " << back[0].index() << ", " << back[1].index() << '\n';
}
@@ -1,2 +0,0 @@
[{"radius":2.0,"type":"circ"},{"height":4.0,"type":"rect","width":3.0}]
alternatives read back: 0, 1
@@ -409,32 +409,6 @@ namespace nlohmann {
} }
``` ```
## Why isn't my `to_json` or `from_json` found?
The library calls `to_json` and `from_json` without qualification, so the compiler finds them by
[argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) in the namespace of the type, or in the
namespaces of its template arguments. The usual reasons for a function that is "not found" are:
- **The type is an alias of a standard type.** After `#!cpp using Hash = std::array<std::uint8_t, 6>;` the type
*is* `std::array<std::uint8_t, 6>`, which lives in namespace `std`. A `to_json(json&, const Hash&)` in your namespace
is never selected. Either give the type its own identity, for example `#!cpp struct Hash : std::array<std::uint8_t, 6> {};`
(the function is then found in `Hash`'s namespace), or specialize
[`adl_serializer<Hash>`](#how-do-i-convert-third-party-types).
- **The function is in the wrong namespace.** It must be in the namespace of the type (a global type needs a global
function), not in the namespace of the code that calls the conversion. Specializations of `adl_serializer` belong in
namespace `nlohmann`.
- **It is declared too late.** A conversion can only use what has been declared when it is instantiated. If
`#!cpp json j = std::vector<third_party::string>{...};` appears before the `adl_serializer` specialization, the
compiler reports an error such as "explicit specialization of `adl_serializer<...>` after instantiation". Put the
specialization in a small header that every file includes **before** it uses the type with `json`.
- **It is a template.** For `template <class T> struct box`, write `template <class T> void to_json(json&, const box<T>&)`,
not an overload for one `T`.
- **It worked by accident.** Some versions found `to_json` overloads in `nlohmann::detail` through argument-dependent
lookup of the base class of `basic_json`. Do not rely on this; it is not part of the interface.
For smart pointers, class hierarchies, `std::variant`, and `std::chrono`, see
[Recipes for common types](type_recipes.md).
## Why can't I convert to/from `std::any`? ## Why can't I convert to/from `std::any`?
`std::any` is intentionally excluded from `get<T>()`/generic conversion support, so `get<std::any>()` and `std::any` is intentionally excluded from `get<T>()`/generic conversion support, so `get<std::any>()` and
@@ -531,7 +505,6 @@ struct bad_serializer
## See also ## See also
- [Recipes for common types](type_recipes.md) - smart pointers, class hierarchies, `std::variant`, and `std::chrono`
- [Converting values](conversions.md) - the general overview of `get`/`get_to` and implicit conversions - [Converting values](conversions.md) - the general overview of `get`/`get_to` and implicit conversions
- [Specializing enum conversion](enum_conversion.md) - map enums to JSON strings instead of integers - [Specializing enum conversion](enum_conversion.md) - map enums to JSON strings instead of integers
- [Supported macros](macros.md) - reference for `NLOHMANN_DEFINE_TYPE_*` and related macros - [Supported macros](macros.md) - reference for `NLOHMANN_DEFINE_TYPE_*` and related macros
+1 -3
View File
@@ -7,9 +7,7 @@ detect bugs in client code.
## Switch off runtime assertions ## Switch off runtime assertions
Runtime assertions can be switched off by defining the preprocessor macro `NDEBUG` (see the Runtime assertions can be switched off by defining the preprocessor macro `NDEBUG` (see the
[documentation of assert](https://en.cppreference.com/w/cpp/error/assert)) which is the default for release builds. Without `NDEBUG`, the assertions are compiled in and contain the name of the source [documentation of assert](https://en.cppreference.com/w/cpp/error/assert)) which is the default for release builds.
file (`__FILE__`); see [notes for builds and distribution](../integration/index.md#notes-for-builds-and-distribution)
if that path must not end up in your binaries.
## Change assertion behavior ## Change assertion behavior
@@ -190,6 +190,41 @@ The library uses the following mapping from JSON values types to BJData types ac
--8<-- "examples/to_bjdata.output" --8<-- "examples/to_bjdata.output"
``` ```
### Byte layout
Consider the following JSON value (shown formatted for readability):
```json
{
"id": 300,
"name": "json",
"pi": 3.14,
"tags": [
"a",
"b"
]
}
```
`to_bjdata` encodes it to 51 bytes (shown in hexadecimal; the encoding contains no whitespace). The colors mark the role of each byte: <span class="bl bl-t">type/marker</span> <span class="bl bl-l">length/count/size</span> <span class="bl bl-d">data</span>.
<div class="byte-layout" markdown="0"><table>
<thead><tr><th>JSON</th><th>Bytes</th><th>Meaning</th></tr></thead><tbody>
<tr><td><code>{</code></td><td><span class="bl bl-t">7B</span></td><td>object start (<code>{</code>)</td></tr>
<tr><td><code>&quot;id&quot;: 300,</code></td><td><span class="bl bl-l">69 02</span> <span class="bl bl-d">69 64</span> <span class="bl bl-t">49</span> <span class="bl bl-d">2C 01</span></td><td>key: length 2 as int8 (<code>i</code>), then UTF-8 bytes; value: int16 (<code>I</code>), little-endian</td></tr>
<tr><td><code>&quot;name&quot;: &quot;json&quot;,</code></td><td><span class="bl bl-l">69 04</span> <span class="bl bl-d">6E 61 6D 65</span> <span class="bl bl-t">53</span> <span class="bl bl-l">69 04</span> <span class="bl bl-d">6A 73 6F 6E</span></td><td>key: length 4; value: string (<code>S</code>), length 4 as int8, UTF-8 bytes</td></tr>
<tr><td><code>&quot;pi&quot;: 3.14,</code></td><td><span class="bl bl-l">69 02</span> <span class="bl bl-d">70 69</span> <span class="bl bl-t">44</span> <span class="bl bl-d">1F 85 EB 51 B8 1E 09 40</span></td><td>key: length 2; value: float64 (<code>D</code>), little-endian</td></tr>
<tr><td><code>&quot;tags&quot;: [</code></td><td><span class="bl bl-l">69 04</span> <span class="bl bl-d">74 61 67 73</span> <span class="bl bl-t">5B</span></td><td>key: length 4; value: array start (<code>[</code>)</td></tr>
<tr><td><code>&quot;a&quot;,</code></td><td><span class="bl bl-t">53</span> <span class="bl bl-l">69 01</span> <span class="bl bl-d">61</span></td><td>string, length 1</td></tr>
<tr><td><code>&quot;b&quot;</code></td><td><span class="bl bl-t">53</span> <span class="bl bl-l">69 01</span> <span class="bl bl-d">62</span></td><td>string, length 1</td></tr>
<tr><td><code>]</code></td><td><span class="bl bl-t">5D</span></td><td>array end (<code>]</code>)</td></tr>
<tr><td><code>}</code></td><td><span class="bl bl-t">7D</span></td><td>object end (<code>}</code>)</td></tr>
</tbody></table></div>
## Deserialization ## Deserialization
The library maps BJData types to JSON value types as follows: The library maps BJData types to JSON value types as follows:
@@ -105,6 +105,41 @@ serialized as 0x81 0x65 0xFF, but `[1,2,3,4,"e"]` as 0x85 0x91 0x92 0x93 0x94 0x
--8<-- "examples/to_bon8.output" --8<-- "examples/to_bon8.output"
``` ```
### Byte layout
Consider the following JSON value (shown formatted for readability):
```json
{
"id": 300,
"name": "json",
"pi": 3.14,
"tags": [
"a",
"b"
]
}
```
`to_bon8` encodes it to 35 bytes (shown in hexadecimal; the encoding contains no whitespace). The colors mark the role of each byte: <span class="bl bl-t">type/marker</span> <span class="bl bl-l">length/count/size</span> <span class="bl bl-d">data</span>.
<div class="byte-layout" markdown="0"><table>
<thead><tr><th>JSON</th><th>Bytes</th><th>Meaning</th></tr></thead><tbody>
<tr><td><code>{</code></td><td><span class="bl bl-t">8A</span></td><td>object with 4 members</td></tr>
<tr><td><code>&quot;id&quot;: 300,</code></td><td><span class="bl bl-d">69 64</span> <span class="bl bl-t">C4</span> <span class="bl bl-d">04</span></td><td>key: UTF-8 bytes; the string ends at the next byte, which cannot continue a UTF-8 character; value: 2-byte positive integer (lead byte, then a byte below 0x80)</td></tr>
<tr><td><code>&quot;name&quot;: &quot;json&quot;,</code></td><td><span class="bl bl-d">6E 61 6D 65</span> <span class="bl bl-l">FF</span> <span class="bl bl-d">6A 73 6F 6E</span> <span class="bl bl-l">FF</span></td><td>key: UTF-8 bytes; 0xFF terminates the string as another string follows; value: UTF-8 bytes; terminated as a string key follows</td></tr>
<tr><td><code>&quot;pi&quot;: 3.14,</code></td><td><span class="bl bl-d">70 69</span> <span class="bl bl-t">8F</span> <span class="bl bl-d">40 09 1E B8 51 EB 85 1F</span></td><td>key: UTF-8 bytes; value: binary64 (IEEE 754, big-endian); its marker also ends <code>&quot;pi&quot;</code></td></tr>
<tr><td><code>&quot;tags&quot;: [</code></td><td><span class="bl bl-d">74 61 67 73</span> <span class="bl bl-t">82</span></td><td>key: UTF-8 bytes; value: array with 2 elements; its marker also ends <code>&quot;tags&quot;</code></td></tr>
<tr><td><code>&quot;a&quot;,</code></td><td><span class="bl bl-d">61</span> <span class="bl bl-l">FF</span></td><td>UTF-8 bytes; terminated as a string follows</td></tr>
<tr><td><code>&quot;b&quot;</code></td><td><span class="bl bl-d">62</span> <span class="bl bl-l">FF</span></td><td>UTF-8 bytes; terminated as nothing follows</td></tr>
<tr><td><code>]</code></td><td></td><td>no end marker: the element count was given up front</td></tr>
<tr><td><code>}</code></td><td></td><td>no end marker: the member count was given up front</td></tr>
</tbody></table></div>
## Deserialization ## Deserialization
The library maps BON8 types to JSON value types as follows: The library maps BON8 types to JSON value types as follows:
@@ -61,6 +61,41 @@ The library uses the following mapping from JSON values types to BSON types:
``` ```
### Byte layout
Consider the following JSON value (shown formatted for readability):
```json
{
"id": 300,
"name": "json",
"pi": 3.14,
"tags": [
"a",
"b"
]
}
```
`to_bson` encodes it to 69 bytes (shown in hexadecimal; the encoding contains no whitespace). The colors mark the role of each byte: <span class="bl bl-t">type/marker</span> <span class="bl bl-l">length/count/size</span> <span class="bl bl-d">data</span>.
<div class="byte-layout" markdown="0"><table>
<thead><tr><th>JSON</th><th>Bytes</th><th>Meaning</th></tr></thead><tbody>
<tr><td><code>{</code></td><td><span class="bl bl-l">45 00 00 00</span></td><td>document size: 69 bytes (int32, little-endian)</td></tr>
<tr><td><code>&quot;id&quot;: 300,</code></td><td><span class="bl bl-t">10</span> <span class="bl bl-d">69 64 00</span> <span class="bl bl-d">2C 01 00 00</span></td><td>int32 element; key as NUL-terminated string; value (little-endian)</td></tr>
<tr><td><code>&quot;name&quot;: &quot;json&quot;,</code></td><td><span class="bl bl-t">02</span> <span class="bl bl-d">6E 61 6D 65 00</span> <span class="bl bl-l">05 00 00 00</span> <span class="bl bl-d">6A 73 6F 6E 00</span></td><td>string element; key; length incl. NUL (int32); NUL-terminated UTF-8 bytes</td></tr>
<tr><td><code>&quot;pi&quot;: 3.14,</code></td><td><span class="bl bl-t">01</span> <span class="bl bl-d">70 69 00</span> <span class="bl bl-d">1F 85 EB 51 B8 1E 09 40</span></td><td>double element; key; value (little-endian)</td></tr>
<tr><td><code>&quot;tags&quot;: [</code></td><td><span class="bl bl-t">04</span> <span class="bl bl-d">74 61 67 73 00</span> <span class="bl bl-l">17 00 00 00</span></td><td>array element; key; embedded document of 23 bytes (keys are the indices)</td></tr>
<tr><td><code>&quot;a&quot;,</code></td><td><span class="bl bl-t">02</span> <span class="bl bl-d">30 00</span> <span class="bl bl-l">02 00 00 00</span> <span class="bl bl-d">61 00</span></td><td>string element; key <code>&quot;0&quot;</code>; length 2; <code>a</code> + NUL</td></tr>
<tr><td><code>&quot;b&quot;</code></td><td><span class="bl bl-t">02</span> <span class="bl bl-d">31 00</span> <span class="bl bl-l">02 00 00 00</span> <span class="bl bl-d">62 00</span></td><td>string element; key <code>&quot;1&quot;</code>; length 2; <code>b</code> + NUL</td></tr>
<tr><td><code>]</code></td><td><span class="bl bl-t">00</span></td><td>end of the array document</td></tr>
<tr><td><code>}</code></td><td><span class="bl bl-t">00</span></td><td>end of the document</td></tr>
</tbody></table></div>
## Deserialization ## Deserialization
The library maps BSON record types to JSON value types as follows: The library maps BSON record types to JSON value types as follows:
@@ -110,6 +110,41 @@ see "binary" cells in the table above.
--8<-- "examples/to_cbor.output" --8<-- "examples/to_cbor.output"
``` ```
### Byte layout
Consider the following JSON value (shown formatted for readability):
```json
{
"id": 300,
"name": "json",
"pi": 3.14,
"tags": [
"a",
"b"
]
}
```
`to_cbor` encodes it to 39 bytes (shown in hexadecimal; the encoding contains no whitespace). The colors mark the role of each byte: <span class="bl bl-t">type/marker</span> <span class="bl bl-l">length/count/size</span> <span class="bl bl-d">data</span>.
<div class="byte-layout" markdown="0"><table>
<thead><tr><th>JSON</th><th>Bytes</th><th>Meaning</th></tr></thead><tbody>
<tr><td><code>{</code></td><td><span class="bl bl-t">A4</span></td><td>map with 4 key/value pairs</td></tr>
<tr><td><code>&quot;id&quot;: 300,</code></td><td><span class="bl bl-t">62</span> <span class="bl bl-d">69 64</span> <span class="bl bl-t">19</span> <span class="bl bl-d">01 2C</span></td><td>key: text string of length 2, then its UTF-8 bytes; value: unsigned integer, 2 bytes follow (big-endian)</td></tr>
<tr><td><code>&quot;name&quot;: &quot;json&quot;,</code></td><td><span class="bl bl-t">64</span> <span class="bl bl-d">6E 61 6D 65</span> <span class="bl bl-t">64</span> <span class="bl bl-d">6A 73 6F 6E</span></td><td>key: text string of length 4; value: text string of length 4</td></tr>
<tr><td><code>&quot;pi&quot;: 3.14,</code></td><td><span class="bl bl-t">62</span> <span class="bl bl-d">70 69</span> <span class="bl bl-t">FB</span> <span class="bl bl-d">40 09 1E B8 51 EB 85 1F</span></td><td>key: text string of length 2; value: double-precision float (IEEE 754, big-endian)</td></tr>
<tr><td><code>&quot;tags&quot;: [</code></td><td><span class="bl bl-t">64</span> <span class="bl bl-d">74 61 67 73</span> <span class="bl bl-t">82</span></td><td>key: text string of length 4; value: array with 2 elements</td></tr>
<tr><td><code>&quot;a&quot;,</code></td><td><span class="bl bl-t">61</span> <span class="bl bl-d">61</span></td><td>text string of length 1</td></tr>
<tr><td><code>&quot;b&quot;</code></td><td><span class="bl bl-t">61</span> <span class="bl bl-d">62</span></td><td>text string of length 1</td></tr>
<tr><td><code>]</code></td><td></td><td>no end marker: the element count was given up front</td></tr>
<tr><td><code>}</code></td><td></td><td>no end marker: the member count was given up front</td></tr>
</tbody></table></div>
## Deserialization ## Deserialization
The library maps CBOR types to JSON value types as follows: The library maps CBOR types to JSON value types as follows:
@@ -45,12 +45,19 @@ See [binary values](../binary_values.md) for more information.
| BJData | 53.2 % | 91.1 % | 78.1 % | 96.6 % | | BJData | 53.2 % | 91.1 % | 78.1 % | 96.6 % |
| BJData (size) | 58.6 % | 92.1 % | 86.7 % | 97.4 % | | BJData (size) | 58.6 % | 92.1 % | 86.7 % | 97.4 % |
| BJData (size+type) | 58.6 % | 92.1 % | 86.5 % | 97.4 % | | BJData (size+type) | 58.6 % | 92.1 % | 86.5 % | 97.4 % |
| BON8 | 50.5 % | 83.8 % | 63.5 % | 87.5 % | | BON8 | **50.5 %** | **83.8 %** | **63.5 %** | **87.5 %** |
| BSON | 85.8 % | 95.2 % | 95.8 % | 106.7 % | | BSON | 85.8 % | 95.2 % | 95.8 % | 106.7 % |
| CBOR | 50.5 % | 86.3 % | 68.4 % | 88.0 % | | CBOR | **50.5 %** | 86.3 % | 68.4 % | 88.0 % |
| MessagePack | 50.5 % | 86.0 % | 68.5 % | 87.9 % | | MessagePack | **50.5 %** | 86.0 % | 68.5 % | 87.9 % |
| UBJSON | 53.2 % | 91.3 % | 78.2 % | 96.6 % | | UBJSON | 53.2 % | 91.3 % | 78.2 % | 96.6 % |
| UBJSON (size) | 58.6 % | 92.3 % | 86.8 % | 97.4 % | | UBJSON (size) | 58.6 % | 92.3 % | 86.8 % | 97.4 % |
| UBJSON (size+type) | 55.9 % | 92.3 % | 85.0 % | 95.0 % | | UBJSON (size+type) | 55.9 % | 92.3 % | 85.0 % | 95.0 % |
Sizes compared to minified JSON value. Sizes compared to minified JSON value; the smallest size per file is printed in bold.
## See also
- [Binary values](../binary_values.md) - binary values and subtypes
- [**to_cbor**](../../api/basic_json/to_cbor.md) / [**from_cbor**](../../api/basic_json/from_cbor.md), [**to_msgpack**](../../api/basic_json/to_msgpack.md) / [**from_msgpack**](../../api/basic_json/from_msgpack.md), [**to_bson**](../../api/basic_json/to_bson.md) / [**from_bson**](../../api/basic_json/from_bson.md), [**to_ubjson**](../../api/basic_json/to_ubjson.md) / [**from_ubjson**](../../api/basic_json/from_ubjson.md), [**to_bjdata**](../../api/basic_json/to_bjdata.md) / [**from_bjdata**](../../api/basic_json/from_bjdata.md), [**to_bon8**](../../api/basic_json/to_bon8.md) / [**from_bon8**](../../api/basic_json/from_bon8.md) - the conversion functions
- [Parsing untrusted input](../parsing/untrusted_input.md)
- [SAX interface](../parsing/sax_interface.md) - decode binary formats without building a value
@@ -91,6 +91,41 @@ specification:
--8<-- "examples/to_msgpack.output" --8<-- "examples/to_msgpack.output"
``` ```
### Byte layout
Consider the following JSON value (shown formatted for readability):
```json
{
"id": 300,
"name": "json",
"pi": 3.14,
"tags": [
"a",
"b"
]
}
```
`to_msgpack` encodes it to 39 bytes (shown in hexadecimal; the encoding contains no whitespace). The colors mark the role of each byte: <span class="bl bl-t">type/marker</span> <span class="bl bl-l">length/count/size</span> <span class="bl bl-d">data</span>.
<div class="byte-layout" markdown="0"><table>
<thead><tr><th>JSON</th><th>Bytes</th><th>Meaning</th></tr></thead><tbody>
<tr><td><code>{</code></td><td><span class="bl bl-t">84</span></td><td>map with 4 key/value pairs</td></tr>
<tr><td><code>&quot;id&quot;: 300,</code></td><td><span class="bl bl-t">A2</span> <span class="bl bl-d">69 64</span> <span class="bl bl-t">CD</span> <span class="bl bl-d">01 2C</span></td><td>key: fixstr of length 2, then its UTF-8 bytes; value: uint 16 (big-endian)</td></tr>
<tr><td><code>&quot;name&quot;: &quot;json&quot;,</code></td><td><span class="bl bl-t">A4</span> <span class="bl bl-d">6E 61 6D 65</span> <span class="bl bl-t">A4</span> <span class="bl bl-d">6A 73 6F 6E</span></td><td>key: fixstr of length 4; value: fixstr of length 4</td></tr>
<tr><td><code>&quot;pi&quot;: 3.14,</code></td><td><span class="bl bl-t">A2</span> <span class="bl bl-d">70 69</span> <span class="bl bl-t">CB</span> <span class="bl bl-d">40 09 1E B8 51 EB 85 1F</span></td><td>key: fixstr of length 2; value: float 64 (IEEE 754, big-endian)</td></tr>
<tr><td><code>&quot;tags&quot;: [</code></td><td><span class="bl bl-t">A4</span> <span class="bl bl-d">74 61 67 73</span> <span class="bl bl-t">92</span></td><td>key: fixstr of length 4; value: fixarray with 2 elements</td></tr>
<tr><td><code>&quot;a&quot;,</code></td><td><span class="bl bl-t">A1</span> <span class="bl bl-d">61</span></td><td>fixstr of length 1</td></tr>
<tr><td><code>&quot;b&quot;</code></td><td><span class="bl bl-t">A1</span> <span class="bl bl-d">62</span></td><td>fixstr of length 1</td></tr>
<tr><td><code>]</code></td><td></td><td>no end marker: the element count was given up front</td></tr>
<tr><td><code>}</code></td><td></td><td>no end marker: the member count was given up front</td></tr>
</tbody></table></div>
## Deserialization ## Deserialization
The library maps MessagePack types to JSON value types as follows: The library maps MessagePack types to JSON value types as follows:
@@ -103,6 +103,41 @@ The library uses the following mapping from JSON values types to UBJSON types ac
--8<-- "examples/to_ubjson.output" --8<-- "examples/to_ubjson.output"
``` ```
### Byte layout
Consider the following JSON value (shown formatted for readability):
```json
{
"id": 300,
"name": "json",
"pi": 3.14,
"tags": [
"a",
"b"
]
}
```
`to_ubjson` encodes it to 51 bytes (shown in hexadecimal; the encoding contains no whitespace). The colors mark the role of each byte: <span class="bl bl-t">type/marker</span> <span class="bl bl-l">length/count/size</span> <span class="bl bl-d">data</span>.
<div class="byte-layout" markdown="0"><table>
<thead><tr><th>JSON</th><th>Bytes</th><th>Meaning</th></tr></thead><tbody>
<tr><td><code>{</code></td><td><span class="bl bl-t">7B</span></td><td>object start (<code>{</code>)</td></tr>
<tr><td><code>&quot;id&quot;: 300,</code></td><td><span class="bl bl-l">69 02</span> <span class="bl bl-d">69 64</span> <span class="bl bl-t">49</span> <span class="bl bl-d">01 2C</span></td><td>key: length 2 as int8 (<code>i</code>), then UTF-8 bytes; value: int16 (<code>I</code>), big-endian</td></tr>
<tr><td><code>&quot;name&quot;: &quot;json&quot;,</code></td><td><span class="bl bl-l">69 04</span> <span class="bl bl-d">6E 61 6D 65</span> <span class="bl bl-t">53</span> <span class="bl bl-l">69 04</span> <span class="bl bl-d">6A 73 6F 6E</span></td><td>key: length 4; value: string (<code>S</code>), length 4 as int8, UTF-8 bytes</td></tr>
<tr><td><code>&quot;pi&quot;: 3.14,</code></td><td><span class="bl bl-l">69 02</span> <span class="bl bl-d">70 69</span> <span class="bl bl-t">44</span> <span class="bl bl-d">40 09 1E B8 51 EB 85 1F</span></td><td>key: length 2; value: float64 (<code>D</code>), big-endian</td></tr>
<tr><td><code>&quot;tags&quot;: [</code></td><td><span class="bl bl-l">69 04</span> <span class="bl bl-d">74 61 67 73</span> <span class="bl bl-t">5B</span></td><td>key: length 4; value: array start (<code>[</code>)</td></tr>
<tr><td><code>&quot;a&quot;,</code></td><td><span class="bl bl-t">53</span> <span class="bl bl-l">69 01</span> <span class="bl bl-d">61</span></td><td>string, length 1</td></tr>
<tr><td><code>&quot;b&quot;</code></td><td><span class="bl bl-t">53</span> <span class="bl bl-l">69 01</span> <span class="bl bl-d">62</span></td><td>string, length 1</td></tr>
<tr><td><code>]</code></td><td><span class="bl bl-t">5D</span></td><td>array end (<code>]</code>)</td></tr>
<tr><td><code>}</code></td><td><span class="bl bl-t">7D</span></td><td>object end (<code>}</code>)</td></tr>
</tbody></table></div>
## Deserialization ## Deserialization
The library maps UBJSON types to JSON value types as follows: The library maps UBJSON types to JSON value types as follows:
-23
View File
@@ -112,29 +112,6 @@ Implicit conversions are convenient but can be surprising (for example, in overl
be disabled by defining [`JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_use_implicit_conversions.md) to `#!cpp 0`, be disabled by defining [`JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_use_implicit_conversions.md) to `#!cpp 0`,
which forces the explicit `get` form and can catch unintended conversions at compile time. which forces the explicit `get` form and can catch unintended conversions at compile time.
!!! warning "`auto` copies the JSON value; it does not convert it"
The type of `#!cpp j["name"]` is `json`, not the C++ type of the value inside. `#!cpp auto` therefore deduces
`json`:
```cpp
json j = {{"name", "Mary"}, {"age", 42}};
auto name = j["name"]; // json: a copy of the value; prints as "Mary" (with quotes)
std::string s1 = j["name"]; // std::string: implicit conversion
auto s2 = j["name"].get<std::string>(); // std::string: explicit conversion
auto& age = j["age"]; // json&: a reference, no copy
age = 43; // changes j
```
This is also why `#!cpp std::cout << j["name"]` prints the quotes (see
[getting a string without quotes](#getting-values-out)), and why a `json` value cannot be passed to `printf`: the
argument is not an `int` or a `char*`, and a compiler either rejects passing it through `...` (Clang does) or
compiles it and prints garbage. Convert first: `#!cpp std::printf("%d", j["age"].get<int>());`.
Prefer `get<T>()` over `auto` when you want the C++ value, and `auto&` or `const auto&` when you want to avoid a
copy of a large value.
!!! warning "Conversions do not range-check numbers" !!! warning "Conversions do not range-check numbers"
Just like C++ itself, the `get` family performs numeric conversions without range checks — retrieving a Just like C++ itself, the `get` family performs numeric conversions without range checks — retrieving a
@@ -59,25 +59,6 @@ with a string as the first element is treated as an object, everything else as a
[FAQ](../home/faq.md#brace-initialization-yields-arrays) for details and the opt-in [FAQ](../home/faq.md#brace-initialization-yields-arrays) for details and the opt-in
[`JSON_BRACE_INIT_COPY_SEMANTICS`](../api/macros/json_brace_init_copy_semantics.md) macro. [`JSON_BRACE_INIT_COPY_SEMANTICS`](../api/macros/json_brace_init_copy_semantics.md) macro.
### What does this produce?
The following table shows how some common spellings are interpreted. When in doubt, use `#!cpp json::array()`,
`#!cpp json::object()`, or the `#!cpp json(value)` form with parentheses.
| code | result | note |
|-------------------------------------------------|------------------------------|----------------------------------------------|
| `#!cpp json j = {};` / `#!cpp json j{};` | `#!json null` | use `json::object()` or `json::array()` |
| `#!cpp json j = json::object();` | `#!json {}` | |
| `#!cpp json j = json::array();` | `#!json []` | |
| `#!cpp json j(true);` | `#!json true` | parentheses create the value itself |
| `#!cpp json j = {true};` | `#!json [true]` | braces create a one-element array (`#!cpp json j{true};` depends on the compiler, see the [FAQ](../home/faq.md#brace-initialization-yields-arrays)) |
| `#!cpp json j = {{"a", 1}};` | `#!json {"a":1}` | all elements are `[string, value]` pairs: object |
| `#!cpp json j = {{"a", 1}, {"b"}};` | `#!json [["a",1],["b"]]` | one element is not a pair: array |
| `#!cpp json j = {{"a", 1}, 2};` | `#!json [["a",1],2]` | a plain value among pairs: array |
| `#!cpp json j = {{"a", 1, 2}};` | `#!json [["a",1,2]]` | a three-element list is not a pair: array |
| `#!cpp json j = "{\"a\":1}";` | `#!json "{\"a\":1}"` | a string **value**; it is not parsed |
| `#!cpp json j = json::parse("{\"a\":1}");` | `#!json {"a":1}` | parse text with `parse` or `_json` |
## Building incrementally ## Building incrementally
A value can also be built up piece by piece. Accessing a non-existing object key or array index with A value can also be built up piece by piece. Accessing a non-existing object key or array index with
@@ -22,41 +22,11 @@ flowchart TD
F -->|"yes"| G["contains() / find()"] F -->|"yes"| G["contains() / find()"]
``` ```
## Does this key exist? ## See also
Use [`contains`](../../api/basic_json/contains.md) to test for a key; it does not modify the value and does not throw: - [**operator[]**](../../api/basic_json/operator%5B%5D.md) - unchecked access
- [**at**](../../api/basic_json/at.md) - checked access
```cpp - [**value**](../../api/basic_json/value.md) - access with default value
json j = {{"name", "Mary"}, {"address", {{"city", "Berlin"}}}}; - [**contains**](../../api/basic_json/contains.md) and [**find**](../../api/basic_json/find.md) - test for existence
- [**front**](../../api/basic_json/front.md) and [**back**](../../api/basic_json/back.md) - first and last element
j.contains("name"); // true - [**items**](../../api/basic_json/items.md) - iterate over keys and values
j.contains("age"); // false
j.contains("city"); // false: contains() only looks at the top level
j["address"].contains("city"); // true
j.contains(json::json_pointer("/address/city")); // true: a JSON pointer tests a nested path in one call
```
If the value is needed afterwards, [`find`](../../api/basic_json/find.md) tests and accesses with a single lookup:
```cpp
if (auto it = j.find("name"); it != j.end())
{
std::cout << *it << '\n';
}
```
`contains` also returns `true` for a key whose value is `null`; use `j.contains("k") && !j["k"].is_null()` if a
`null` should count as missing. To read a value with a fallback instead, see [`value`](default_value.md).
!!! warning "`operator[]` inserts missing keys"
Like `#!cpp std::map::operator[]`, the non-const [`operator[]`](unchecked_access.md) adds a `null` value if the key
is missing. Testing a key with it therefore *changes the object*:
```cpp
json j = {{"foo", 1}};
bool absent = j["bar"].is_null(); // true, but j is now {"bar": null, "foo": 1}
```
Use `contains`/`find` to test, and [`at`](checked_access.md) to access a value that must exist (it throws an
[`out_of_range`](../../home/exceptions.md#out-of-range) exception otherwise).
+8
View File
@@ -59,3 +59,11 @@ C++ types, and finally serialize it again.
This section gives conceptual overviews. For the precise signature, parameters, and return value of a function, see This section gives conceptual overviews. For the precise signature, parameters, and return value of a function, see
the [API Documentation](../api/basic_json/index.md). the [API Documentation](../api/basic_json/index.md).
## See also
- [API documentation](../api/basic_json/index.md) - reference of all classes and functions
- [FAQ](../home/faq.md) - answers to common questions
- [Exceptions](../home/exceptions.md) - all exceptions and their error codes
- [Design goals](../home/design_goals.md)
- [Integration](../integration/index.md) - how to add the library to a project
-113
View File
@@ -1,113 +0,0 @@
# Working Without Exceptions
By default, the library reports errors by throwing exceptions (see [Exceptions](../home/exceptions.md)). This page
collects what to use when exceptions are unwanted or unavailable, for example in embedded systems, game engines, or
code compiled with `-fno-exceptions`.
## Two different questions
1. **Can my code avoid *catching* exceptions?** Yes. For parsing and for accessing values there are functions that
report failure through a return value. They work in a normal build and need no `#!cpp try`/`#!cpp catch`.
2. **Can the library be *compiled* without exceptions?** Yes, with `-fno-exceptions` or by defining
[`JSON_NOEXCEPTION`](../api/macros/json_noexception.md). Both have the same effect: every `#!cpp throw` in the
library becomes a call to `std::abort()`. The functions listed below never reach a `#!cpp throw` for the failures
they report, so they keep working in this configuration. Anything else that fails aborts the program.
## Parsing
| function | on invalid input |
|---------------------------------------------------------------------------------------------|-----------------------------------------------------|
| `#!cpp json::parse(input, nullptr, false)` | returns a *discarded* value; test with `is_discarded()` |
| [`accept`](../api/basic_json/accept.md) | returns `#!cpp false` |
| `#!cpp json::from_cbor(input, true, false)` (and the other `from_*` functions) | returns a *discarded* value |
| [`sax_parse`](../api/basic_json/sax_parse.md) with your own handler | returns `#!cpp false` after calling `parse_error` |
??? example "Example: parse and validate without exceptions"
```cpp
--8<-- "examples/no_exceptions_parse.cpp"
```
Output:
```
--8<-- "examples/no_exceptions_parse.output"
```
None of the calls in this example throws, so it also compiles and runs with `-fno-exceptions`.
The discarded value carries no message. If you need the position or the reason, use the SAX interface; see
[Parsing and exceptions](parsing/parse_exceptions.md).
## Accessing values
The access functions are not equally safe. Only some of them never throw:
| expression | if the key is missing or the type is wrong |
|-------------------------------------|-------------------------------------------------------------------------------|
| `#!cpp j.contains("k")` | returns `#!cpp false` for a missing key; never throws |
| `#!cpp j.find("k")` | returns `end()` for a missing key; never throws |
| `#!cpp j.is_string()`, ... | the `is_*` functions test the type; never throw |
| `#!cpp j.get_ptr<const std::string*>()` | returns `#!cpp nullptr` for a different type; never throws |
| `#!cpp j.at("k")` | throws `out_of_range.403` for a missing key |
| `#!cpp j.get<int>()` | throws `type_error.302` for a value that is not a number |
| `#!cpp j.value("k", 0)` | returns the default for a missing key, but **throws `type_error.302` if `k` exists with another type** |
| `#!cpp j["k"]` (non-const) | inserts `null` for a missing key |
| `#!cpp j["k"]` (const) | undefined behavior for a missing key |
So reading a value that may be absent or of the wrong type without exceptions takes two steps: look up, then test the
type.
??? example "Example: look up a key and test its type"
```cpp
--8<-- "examples/no_exceptions_access.cpp"
```
Output:
```
--8<-- "examples/no_exceptions_access.output"
```
The last lines of the example show why `value` is not on the safe list: it returns the default only for a *missing*
key.
For numbers, test with `is_number()` (or `is_number_integer()`, `is_number_unsigned()`, `is_number_float()`) before
calling `get<int>()`, and see [number handling](types/number_handling.md) for range and precision. Whether a value
fits into the target type is not checked by `get`.
## Converting to your own types
`from_json` functions (including the ones generated by the
[`NLOHMANN_DEFINE_TYPE_*` macros](arbitrary_types.md#simplify-your-life-with-macros)) report problems by throwing.
There is no variant that returns an error code. Without exceptions you have two options:
- Validate the JSON value yourself, as shown above, and fill your struct field by field.
- Convert in a function that is compiled **with** exceptions enabled and catches them at the boundary, returning
`std::optional` or an error code to the rest of your code:
??? example "Example: convert to a struct and report failure as std::optional"
```cpp
--8<-- "examples/no_exceptions_convert.c++17.cpp"
```
Output:
```
--8<-- "examples/no_exceptions_convert.c++17.output"
```
## Overriding what happens instead of an exception
With exceptions off, you can replace the `abort()` by your own code, for example to log the message first. See
[Switch off exceptions](../home/exceptions.md#switch-off-exceptions) and
[`JSON_THROW_USER`](../api/macros/json_throw_user.md). The handler must not return normally.
## See also
- [Exceptions](../home/exceptions.md) - all exceptions and their ids
- [Parsing and exceptions](parsing/parse_exceptions.md) - the parsing alternatives in detail
- [Parsing untrusted input](parsing/untrusted_input.md)
- [`JSON_NOEXCEPTION`](../api/macros/json_noexception.md)
+2 -13
View File
@@ -33,9 +33,7 @@ json data = json::parse(f);
``` ```
The input must be encoded in UTF-8; other encodings are not supported. A single input may contain only one JSON value. The input must be encoded in UTF-8; other encodings are not supported. A single input may contain only one JSON value.
Inputs consisting of multiple values separated by newlines are handled by the [JSON Lines](json_lines.md) format; input Inputs consisting of multiple values separated by newlines are handled by the [JSON Lines](json_lines.md) format.
that arrives in chunks or contains several values is covered in
[Large, streamed, and partial input](large_and_partial_input.md).
By default, the library rejects comments and trailing commas. Both can be enabled with parameters of the `parse` By default, the library rejects comments and trailing commas. Both can be enabled with parameters of the `parse`
function — see [comments](../comments.md) and [trailing commas](../trailing_commas.md). function — see [comments](../comments.md) and [trailing commas](../trailing_commas.md).
@@ -87,7 +85,7 @@ again without changing any result.
## SAX vs. DOM parsing ## SAX vs. DOM parsing
The library offers two parsing models, and a third, read-only alternative: The library offers two parsing models:
- **DOM parsing** (the default): the complete input is read and stored as an in-memory `basic_json` value that can be - **DOM parsing** (the default): the complete input is read and stored as an in-memory `basic_json` value that can be
traversed and modified freely. This is what [`parse`](../../api/basic_json/parse.md) does, and it is the right choice traversed and modified freely. This is what [`parse`](../../api/basic_json/parse.md) does, and it is the right choice
@@ -97,13 +95,6 @@ The library offers two parsing models, and a third, read-only alternative:
inputs or when you only need to extract parts of the input. See the [SAX interface](sax_interface.md) for details and inputs or when you only need to extract parts of the input. See the [SAX interface](sax_interface.md) for details and
[`sax_parse`](../../api/basic_json/sax_parse.md) for the API. [`sax_parse`](../../api/basic_json/sax_parse.md) for the API.
- **Document and views** (`#!cpp <nlohmann/json_view.hpp>`, added in version 3.13.0): [`json_document::parse`](../../api/basic_json_document/parse.md)
reads the same JSON grammar but builds a flat, read-only index of the values instead of a `basic_json` tree. Strings and
floating-point numbers are read from the text on demand, and only the parts you
[`materialize()`](../../api/basic_json_view/materialize.md) become `basic_json` values. This avoids most of the work when you
need only a few values from a large or frequently parsed text; see [Zero-copy JSON views](../json_view.md). It is read-only, so use
`parse` when you need to modify the value.
You can influence a DOM parse without switching to the SAX interface by passing a You can influence a DOM parse without switching to the SAX interface by passing a
[parser callback](parser_callbacks.md), which is called during parsing and can, for example, discard parts of the input. [parser callback](parser_callbacks.md), which is called during parsing and can, for example, discard parts of the input.
@@ -120,9 +111,7 @@ options.
- [`accept`](../../api/basic_json/accept.md) - check if the input is valid JSON - [`accept`](../../api/basic_json/accept.md) - check if the input is valid JSON
- [`sax_parse`](../../api/basic_json/sax_parse.md) - generate SAX events - [`sax_parse`](../../api/basic_json/sax_parse.md) - generate SAX events
- [JSON Lines](json_lines.md) - parse newline-delimited JSON - [JSON Lines](json_lines.md) - parse newline-delimited JSON
- [Large, streamed, and partial input](large_and_partial_input.md) - chunked, concatenated, and very large input
- [parser callbacks](parser_callbacks.md) - influence the parsing by a callback function - [parser callbacks](parser_callbacks.md) - influence the parsing by a callback function
- [SAX interface](sax_interface.md) - implement a custom SAX handler - [SAX interface](sax_interface.md) - implement a custom SAX handler
- [Zero-copy JSON views](../json_view.md) - parse into a read-only document and read it through views
- [parsing and exceptions](parse_exceptions.md) - control error handling - [parsing and exceptions](parse_exceptions.md) - control error handling
- [parsing untrusted input](untrusted_input.md) - what to consider when parsing input from untrusted sources - [parsing untrusted input](untrusted_input.md) - what to consider when parsing input from untrusted sources
@@ -1,154 +0,0 @@
# Large, Streamed, and Partial Input
[`parse`](../../api/basic_json/parse.md) reads exactly one complete JSON value and builds it in memory. It cannot be
paused and resumed, and it does not hand back a half-parsed value when the input ends early. This page shows what to do
when the input does not fit that model: it arrives in pieces, it contains several values, or it is too large to hold
as a `json` value.
```mermaid
flowchart TD
A["my input is..."] --> B{"several JSON values in one stream?"}
B -->|"yes"| C["read them one at a time"]
A --> D{"arriving in chunks (socket, pipe)?"}
D -->|"yes"| E["frame the messages, or buffer until complete"]
A --> F{"too large to keep in memory?"}
F -->|"yes"| G["discard parts with a callback, or use SAX"]
A --> H{"only a small part is needed?"}
H -->|"yes"| I["stop early with SAX, or read through a view"]
```
## Several values in one stream
For newline-delimited input, read line by line and parse each line, as described in [JSON Lines](json_lines.md). For
values that are simply concatenated, [`operator>>`](../../api/operator_gtgt.md) reads one value and leaves the stream
positioned after it. Check for the end of the stream before each read, because a read at the end throws:
??? example "Example: read concatenated values"
```cpp
--8<-- "examples/partial_input_concatenated.cpp"
```
Output:
```
--8<-- "examples/partial_input_concatenated.output"
```
The same works for binary formats. [`from_cbor`](../../api/basic_json/from_cbor.md) and its relatives accept
`#!cpp strict = false` to stop after the first value and leave the rest of the stream untouched; `tellg()` then reports
how many bytes the value took:
??? example "Example: read one CBOR value and find out how many bytes it used"
```cpp
--8<-- "examples/partial_input_cbor.cpp"
```
Output:
```
--8<-- "examples/partial_input_cbor.output"
```
## Input arriving in chunks
A socket, pipe, or HTTP body hands over data in pieces of arbitrary size, and a piece can end in the middle of a
number, a string, or an object. The parser does not keep state between calls, so there are two ways to deal with this.
**Frame the messages.** The most robust approach is a protocol that says where a value ends: one value per line
([JSON Lines](json_lines.md)), a length prefix, or a delimiter. Collect the bytes of one message and parse them when
the frame is complete. Prefer this whenever you control the protocol.
**Buffer until the value is complete.** If the data has no framing, append every chunk to a buffer and try to parse
it. A parse error at the very end of the buffer means that the input ended prematurely, while an error anywhere else is
a real syntax error. The member `byte` of the [`parse_error`](../../home/exceptions.md#jsonexceptionparse_error101)
exception is one past the buffer size in the first case:
??? example "Example: buffer chunks until the value is complete"
```cpp
--8<-- "examples/partial_input_buffering.cpp"
```
Output:
```
--8<-- "examples/partial_input_buffering.output"
```
The example feeds a document in five chunks. The first four are reported as incomplete, and a syntax error is reported as
such, not as missing data.
!!! warning "Limits of buffering"
- The buffer must contain exactly one value. Data that belongs to the next value is a syntax error. Use framing if
values follow each other without a separator.
- A number at the end of the buffer is a complete value, even if more digits are still to come (`12` may be the
start of `123`). Buffering cannot detect this; use framing for top-level numbers.
- Every attempt parses the buffer from the beginning, so the total work grows quadratically with the size of the
value. Limit the size of the buffer for input you do not trust (see [untrusted input](untrusted_input.md)).
## Input too large for memory
The input does not have to become one huge `json` value. The two tools below process it piece by piece.
### Handle and discard elements with a callback
A [parser callback](parser_callbacks.md) is called for every finished value. If it returns `#!cpp false`, the value is
discarded and its memory is released at once. For a file that consists of one huge array (or one huge object) of
records, handle each record at depth 1 and discard it:
??? example "Example: handle and discard each record of a large array"
```cpp
--8<-- "examples/partial_input_discard_records.cpp"
```
Output:
```
--8<-- "examples/partial_input_discard_records.output"
```
Only one record is in memory at any time. The same recipe, with more detail, is in the
[parser callbacks](parser_callbacks.md#recipe-streaming-a-large-homogeneous-array) page. To skip entire members you do not
need, discard them when their key is read; see the [example](parser_callbacks.md) for `parse_event_t::key`.
### Extract a few values and stop with SAX
With the [SAX interface](sax_interface.md), no value is built at all, and **returning `#!cpp false` from any handler
function stops the parser**. [`sax_parse`](../../api/basic_json/sax_parse.md) then returns `#!cpp false`, and the rest
of the input is not read. The example finds the first `id` in a document without parsing the remainder:
??? example "Example: stop parsing as soon as a value is found"
```cpp
--8<-- "examples/partial_input_sax_stop.cpp"
```
Output:
```
--8<-- "examples/partial_input_sax_stop.output"
```
Note that `sax_parse` returns `#!cpp false` both when a handler stopped the parse and when the input is invalid, so
record the reason in the handler (here: `id`) if you need to tell the two apart.
### Read parts of a large document with a view
If the whole text is available and you only need to read some of it, a [`json_document`](../json_view.md) from
`<nlohmann/json_view.hpp>` (added in version 3.13.0) avoids the `basic_json` tree altogether: it keeps the text, builds a flat index of the values,
and gives read-only [views](../../api/basic_json_view/index.md) of the parts you look at. Only what you
[`materialize()`](../../api/basic_json_view/materialize.md) becomes a `basic_json` value. See
[Zero-copy JSON views](../json_view.md) for details and for the lifetime rules.
## See also
- [Parsing](index.md) - overview of the parsing functions
- [JSON Lines](json_lines.md) - newline-delimited JSON
- [Parser callbacks](parser_callbacks.md) - discard values while parsing
- [SAX interface](sax_interface.md) - event-based parsing
- [Zero-copy JSON views](../json_view.md) - read parts of a large document without building a tree
- [Untrusted input](untrusted_input.md) - limits for input you do not control
@@ -21,10 +21,6 @@ catch (json::parse_error& ex)
In case exceptions are undesired or not supported by the environment, there are different ways to proceed: In case exceptions are undesired or not supported by the environment, there are different ways to proceed:
!!! tip
[Working without exceptions](../no_exceptions.md) also covers accessing values and converting to your own types.
## Switch off exceptions ## Switch off exceptions
The [`parse()`](../../api/basic_json/parse.md) function accepts a `#!cpp bool` parameter `allow_exceptions` which The [`parse()`](../../api/basic_json/parse.md) function accepts a `#!cpp bool` parameter `allow_exceptions` which
@@ -85,61 +81,3 @@ The return value indicates whether the parsing should continue, so the function
``` ```
--8<-- "examples/sax_no_exception.output" --8<-- "examples/sax_no_exception.output"
``` ```
## Where did the error occur?
The message of a [`parse_error`](../../home/exceptions.md#jsonexceptionparse_error101) for JSON text contains the line
and column of the error:
```
[json.exception.parse_error.101] parse error at line 3, column 8: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
```
The exception object itself only stores the **byte index** of the last read character in the member `byte` (the first
byte of the input has index 1). The same index is passed to `parse_error` in the [SAX interface](sax_interface.md). If
you need the line and column as numbers, for example to show them in an editor, compute them from the input:
??? example "Example: compute line and column of a parse error"
```cpp
--8<-- "examples/parse_error_position.cpp"
```
Output:
```
--8<-- "examples/parse_error_position.output"
```
Columns count bytes, so a line with multi-byte UTF-8 characters before the error may differ from the column your editor
shows.
### Where is the value that caused a later error?
A `parse_error` is raised while the text is read. Many mistakes show up later: the text is valid JSON, but a value has
the wrong type when you convert it (`type_error.302`), or a key is missing (`out_of_range.403`). The exception then says
what is wrong, but not where in the input the value was. Define
[`JSON_DIAGNOSTIC_POSITIONS`](../../api/macros/json_diagnostic_positions.md) before including the library to add the
byte range of the offending value to such messages (since version 3.12.0), and to query the range of any value with
[`start_pos()`](../../api/basic_json/start_pos.md) and [`end_pos()`](../../api/basic_json/end_pos.md):
??? example "Example: locate a value with diagnostic positions"
```cpp
--8<-- "examples/parse_error_position_diagnostic.cpp"
```
Output:
```
--8<-- "examples/parse_error_position_diagnostic.output"
```
Positions are only available for values created by [`parse`](../../api/basic_json/parse.md), they are not updated when a
value is changed, and the macro makes every value 16 bytes larger on 64-bit platforms, so use it where the cost is
acceptable, for example for configuration files. Note that `start_pos()` is a 0-based index into the input, whereas
`byte` of a `parse_error` starts at 1.
For binary formats such as CBOR, there are no lines; `byte` is the position in the byte sequence. To find out how many
bytes a successfully parsed value used, see
[Several values in one stream](large_and_partial_input.md#several-values-in-one-stream).
@@ -26,11 +26,9 @@ several alternatives; see [Parsing and exceptions](parse_exceptions.md) for the
[example](parse_exceptions.md#user-defined-sax-interface) that overrides it to print instead of throw. [example](parse_exceptions.md#user-defined-sax-interface) that overrides it to print instead of throw.
If exceptions are unavailable entirely (`-fno-exceptions`, or [`JSON_NOEXCEPTION`](../../api/macros/json_noexception.md) If exceptions are unavailable entirely (`-fno-exceptions`, or [`JSON_NOEXCEPTION`](../../api/macros/json_noexception.md)
defined), every `#!cpp throw` in the library becomes a call to `std::abort()`. The alternatives above do not throw, so defined), every `#!cpp throw` in the library becomes a call to `std::abort()` -- there is no way to recover from a
`parse()` with `allow_exceptions` set to `#!cpp false` (and likewise `accept()` and the `from_*` functions with parse error of untrusted input in that configuration; see
`allow_exceptions` set to `#!cpp false`) can still reject invalid input in that configuration; a plain `parse()` call [Switch off exceptions](../../home/exceptions.md#switch-off-exceptions) for the details and for overriding this with
aborts on invalid input. See [Working without exceptions](../no_exceptions.md) and
[Switch off exceptions](../../home/exceptions.md#switch-off-exceptions) for the details and for overriding the abort with
`JSON_THROW_USER`. `JSON_THROW_USER`.
## Nesting depth ## Nesting depth
+1 -26
View File
@@ -122,9 +122,7 @@ an adapter, since their template argument order does not match what `basic_json`
[linear in its size](../api/basic_json/basic_json.md#complexity) for the copy constructor but [linear in its size](../api/basic_json/basic_json.md#complexity) for the copy constructor but
[constant](../api/basic_json/basic_json.md#complexity) for the move constructor. The same applies to assigning a [constant](../api/basic_json/basic_json.md#complexity) for the move constructor. The same applies to assigning a
large `#!cpp std::string`, `#!cpp std::vector`, or other container into a value: pass it as `#!cpp std::move(x)` large `#!cpp std::string`, `#!cpp std::vector`, or other container into a value: pass it as `#!cpp std::move(x)`
rather than `x` whenever `x` is no longer needed afterwards. Since version 3.13.0, converting an rvalue container rather than `x` whenever `x` is no longer needed afterwards.
(`#!cpp json j = std::move(vec);`) moves the elements instead of copying them; the source is then left in a valid but
unspecified state.
- **Access without copying.** [`get<T>()`](../api/basic_json/get.md) returns a copy of the stored value converted to - **Access without copying.** [`get<T>()`](../api/basic_json/get.md) returns a copy of the stored value converted to
`T`. When a reference or pointer to the value already stored inside the `basic_json` is enough, `T`. When a reference or pointer to the value already stored inside the `basic_json` is enough,
[`get_ref()`](../api/basic_json/get_ref.md) and [`get_ptr()`](../api/basic_json/get_ptr.md) access it directly: [`get_ref()`](../api/basic_json/get_ref.md) and [`get_ptr()`](../api/basic_json/get_ptr.md) access it directly:
@@ -153,29 +151,6 @@ an adapter, since their template argument order does not match what `basic_json`
["reserving array capacity"](element_access/unchecked_access.md#performance-reserving-array-capacity) for the ["reserving array capacity"](element_access/unchecked_access.md#performance-reserving-array-capacity) for the
one-line recipe. one-line recipe.
## Memory
- **A value is small, its content is on the heap.** A `basic_json` is 16 bytes on a 64-bit platform (a type tag and a
union). Strings, arrays, objects, and binary values are allocated on the heap and owned by the value. Destroying the
value frees everything it owns.
- **Copies are deep.** After `#!cpp json b = a;`, changing `b` does not change `a`, and both own their memory. Copying a
large value therefore doubles its memory; see [Avoiding copies](#avoiding-copies). `#!cpp auto x = j["key"];` is a
copy, `#!cpp auto& x = j["key"];` is not.
- **A moved-from value is `null`.** After `#!cpp json c = std::move(a);` the value `a` is `#!json null` and owns nothing.
- **Reading does not require a tree.** If you only read the data, parse it into a [`json_document`](json_view.md)
(`#!cpp <nlohmann/json_view.hpp>`, added in version 3.13.0) instead of a `basic_json`. It stores 16 bytes per value, does not copy floating-point
numbers or strings without escape sequences out of the text, and creates no `basic_json` value except for the parts
you [`materialize()`](../api/basic_json_view/materialize.md). A document that borrows the text needs the text to
outlive it; see [Zero-copy JSON views](json_view.md).
- **Containers keep their capacity.** `clear()` and `erase()` on an array remove the elements, but the underlying
`#!cpp std::vector` keeps its allocated capacity, like `#!cpp std::vector::clear` does. To give the memory back,
assign a new value (`#!cpp j = json::array();`) or destroy the value.
- **Freed memory does not always go back to the operating system.** The library returns memory to the allocator
(`#!cpp std::allocator` by default, or the [one you configured](types/template_parameters.md)). Whether the process
size shrinks then depends on the allocator and the platform, as for any C++ program. A process that parses a large
document and drops it is not leaking if its resident size stays high; run it under a tool such as
[Valgrind](https://valgrind.org) or the sanitizers to tell a leak from retained memory.
## Serialization ## Serialization
[`dump()`](../api/basic_json/dump.md) with the default `#!cpp indent = -1` selects "the most compact representation" [`dump()`](../api/basic_json/dump.md) with the default `#!cpp indent = -1` selects "the most compact representation"
-122
View File
@@ -1,122 +0,0 @@
# Recipes for Common Types
The library converts the standard containers, strings, numbers, tuples, `std::optional`, and `std::filesystem::path`
(the last two since version 3.12.0, C++17) out of the box, and your own types once you write conversion functions or use
the macros (see [Arbitrary type conversions](arbitrary_types.md)). It deliberately does **not** convert smart pointers,
`std::variant`, `std::chrono` types, or class hierarchies, because there is more than one reasonable JSON
representation for each of them. This page shows a representation for each that you can copy and adapt.
All recipes use a specialization of [`adl_serializer`](../api/adl_serializer/index.md), which you may provide for types
you do not own, or free `to_json`/`from_json` functions in the namespace of the type. Place them where they are
visible before any code that converts the type; see
[Why isn't my `to_json` found?](arbitrary_types.md#why-isnt-my-to_json-or-from_json-found).
## Smart pointers
A `std::shared_ptr<T>` or `std::unique_ptr<T>` is written as the value it points to, or as `#!json null` for an empty
pointer, and read back by allocating a new `T`:
??? example "Example: serialize shared_ptr and unique_ptr"
```cpp
--8<-- "examples/type_recipes_smart_pointers.c++14.cpp"
```
Output:
```
--8<-- "examples/type_recipes_smart_pointers.c++14.output"
```
With this, containers of smart pointers, pointers to `const`, and members of these types in your own structs convert as
usual. A pointer to a base class cannot be filled this way, because `T` would have
to be created as a derived type; see the next section.
Reading creates a new object. Two `shared_ptr`s that pointed to the same object are written twice and read back as two
separate objects.
## Class hierarchies
!!! tip "Derived classes whose type is known at compile time"
If you only need to serialize the data members of a derived class, and the code always knows the concrete type, you do
not need a type tag. The [`NLOHMANN_DEFINE_DERIVED_TYPE_*` macros](arbitrary_types.md#simplify-your-life-with-macros)
(since version 3.12.0) add the members of the derived class to those of its base class. This section is for the case
where the concrete type is only known at run time, such as a `std::unique_ptr<shape>` that holds a circle or a
rectangle.
JSON has no notion of types, so a value in a hierarchy needs a **type tag** that says which derived class to create.
Write the tag in the object, and select the class from it when reading:
??? example "Example: serialize a class hierarchy with a type tag"
```cpp
--8<-- "examples/type_recipes_class_hierarchy.c++14.cpp"
```
Output:
```
--8<-- "examples/type_recipes_class_hierarchy.c++14.output"
```
A `#!cpp std::vector<std::unique_ptr<shape>>` converts to an array of tagged objects and back, creating a `circle`
and a `rectangle`. The same works for `std::shared_ptr<shape>`. Remember the virtual destructor: without it, deleting a
derived object through the base pointer is undefined behavior.
## `std::variant`
A variant has the same problem: the alternative must be recorded. If the alternatives are your own types, write a type
tag next to their members, exactly as for a hierarchy:
??? example "Example: serialize a std::variant with a type tag"
```cpp
--8<-- "examples/type_recipes_variant.c++17.cpp"
```
Output:
```
--8<-- "examples/type_recipes_variant.c++17.output"
```
In the example, the functions are found
because `geo` is the namespace of the template arguments of `#!cpp std::variant<circ, rect>`; for a variant of only
standard types (for example `#!cpp std::variant<int, std::string>`) there is no such namespace, and you need an
`adl_serializer` specialization or a wrapper type of your own.
If the alternatives are JSON-native (numbers, strings, ...), a variant such as `#!cpp std::variant<int, std::string>`
can instead be written as the plain value, and read by testing the JSON type (`is_number_integer()`, `is_string()`)
to choose the alternative.
## `std::chrono`
A duration is written as its count and read back with the same representation and period. The **unit is not part of
the JSON value**, so document it, for example in the member name (`timeout_ms`):
??? example "Example: serialize durations and system_clock time points"
```cpp
--8<-- "examples/type_recipes_chrono.cpp"
```
Output:
```
--8<-- "examples/type_recipes_chrono.output"
```
A `system_clock::time_point` with millisecond precision is written as the number of milliseconds since the Unix epoch.
The time point serializer is limited to `system_clock`,
because the epoch of other clocks (for example `steady_clock`) has no meaning outside the running program.
If you prefer a text representation such as ISO 8601 (`2023-11-14T22:13:20Z`), write the string with
`#!cpp std::format("{:%FT%TZ}", t)` and read it with `std::chrono::parse` (both C++20), or with a date library, in the
same two functions.
## See also
- [Arbitrary type conversions](arbitrary_types.md) - the conversion mechanism and macros
- [Why isn't my `to_json` found?](arbitrary_types.md#why-isnt-my-to_json-or-from_json-found)
- [Converting values](conversions.md) - `get`, implicit conversions, and `std::optional`
Loaded 100 of 156 files, more files were not shown because too many files have changed in this diff. Show more