mirror of
https://github.com/nlohmann/json.git
synced 2026-09-05 15:57:58 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1961144874 | ||
|
|
216f57f43b | ||
|
|
207db0f124 | ||
|
|
b38c4cc937 | ||
|
|
6d73dd94b2 | ||
|
|
eea976435b | ||
|
|
7c39f3227e | ||
|
|
a85063ea52 | ||
|
|
911273162a | ||
|
|
e024fe5fb6 | ||
|
|
a4e09fa5b7 | ||
|
|
626fdb098a | ||
|
|
bfaf253f09 | ||
|
|
e1dfc65814 | ||
|
|
17d6fa753b | ||
|
|
37073ea8b5 | ||
|
|
17362c3417 | ||
|
|
0da083744a | ||
|
|
5a2b8a274d | ||
|
|
8ce64b9c16 | ||
|
|
3b28316ee4 | ||
|
|
22c8a9554f | ||
|
|
43afb5bebc | ||
|
|
110cd31e8f | ||
|
|
0e4ad2e8da | ||
|
|
ccb290facf | ||
|
|
26b10a7b18 | ||
|
|
690c3be01d | ||
|
|
ca47dd539d | ||
|
|
681fb07eb2 | ||
|
|
a02741fd28 | ||
|
|
b8482ed7f4 | ||
|
|
d386e0aa52 | ||
|
|
5d93f35463 | ||
|
|
96806af2dc | ||
|
|
7a37a27a67 | ||
|
|
06feaa8d04 | ||
|
|
b1c9a68b9b | ||
|
|
599bb1b68c |
@@ -38,14 +38,14 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||||
with:
|
with:
|
||||||
languages: c-cpp
|
languages: c-cpp
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
uses: github/codeql-action/autobuild@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||||
|
|||||||
@@ -43,6 +43,6 @@ jobs:
|
|||||||
output: 'flawfinder_results.sarif'
|
output: 'flawfinder_results.sarif'
|
||||||
|
|
||||||
- name: Upload analysis results to GitHub Security tab
|
- name: Upload analysis results to GitHub Security tab
|
||||||
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||||
with:
|
with:
|
||||||
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
||||||
|
|||||||
@@ -76,6 +76,6 @@ jobs:
|
|||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
|
|
||||||
# Upload SARIF file generated in previous step
|
# Upload SARIF file generated in previous step
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
|
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||||
with:
|
with:
|
||||||
sarif_file: semgrep.sarif
|
sarif_file: semgrep.sarif
|
||||||
if: always()
|
if: always()
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ To store objects in C++, a type is defined by the template parameters explained
|
|||||||
## Template parameters
|
## Template parameters
|
||||||
|
|
||||||
`ArrayType`
|
`ArrayType`
|
||||||
: container type to store arrays (e.g., `std::vector` or `std::list`)
|
: container type to store arrays. It must be a vector-like container: the library uses `operator[]`, `at()`, and
|
||||||
|
`resize()`, and requires random-access iterators. `#!cpp std::vector` and `#!cpp std::deque` qualify;
|
||||||
|
`#!cpp std::list` does not. See
|
||||||
|
[Template Parameter Requirements](../../features/types/template_parameters.md#arraytype) for the full list of
|
||||||
|
requirements.
|
||||||
|
|
||||||
`AllocatorType`
|
`AllocatorType`
|
||||||
: the allocator to use for objects (e.g., `std::allocator`)
|
: the allocator to use for objects (e.g., `std::allocator`)
|
||||||
@@ -66,3 +70,4 @@ Arrays are stored as pointers in a `basic_json` type. That is, for any access to
|
|||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 1.0.0.
|
- Added in version 1.0.0.
|
||||||
|
- Made `capacity()` optional, so that array types such as `#!cpp std::deque` can be used, in version 3.13.0.
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ represent a byte array in modern C++.
|
|||||||
`value_type` must additionally be exactly one byte wide (e.g., `std::uint8_t`/`char`/`std::byte`): the binary
|
`value_type` must additionally be exactly one byte wide (e.g., `std::uint8_t`/`char`/`std::byte`): the binary
|
||||||
serializers (CBOR, MessagePack, BSON, UBJSON) read and write the container's raw bytes via
|
serializers (CBOR, MessagePack, BSON, UBJSON) read and write the container's raw bytes via
|
||||||
`reinterpret_cast`, which is only correct for byte-sized elements -- a container like
|
`reinterpret_cast`, which is only correct for byte-sized elements -- a container like
|
||||||
`#!cpp std::vector<std::intptr_t>` will not work as `BinaryType`.
|
`#!cpp std::vector<std::intptr_t>` will not work as `BinaryType`. The elements must be stored contiguously, and
|
||||||
|
the binary readers additionally require `resize()` and `operator[]`. See
|
||||||
|
[Template Parameter Requirements](../../features/types/template_parameters.md#binarytype) for the full list.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
@@ -50,6 +52,11 @@ represent a byte array in modern C++.
|
|||||||
|
|
||||||
The default values for `BinaryType` is `#!cpp std::vector<std::uint8_t>`.
|
The default values for `BinaryType` is `#!cpp std::vector<std::uint8_t>`.
|
||||||
|
|
||||||
|
#### Supported byte types
|
||||||
|
|
||||||
|
`#!cpp std::vector<std::uint8_t>`, `#!cpp std::vector<char>`, and `#!cpp std::vector<std::byte>` are supported.
|
||||||
|
Regardless of which of them is configured, [`dump`](dump.md) writes the bytes as the numbers 0..255.
|
||||||
|
|
||||||
#### Custom BinaryType behavior
|
#### Custom BinaryType behavior
|
||||||
|
|
||||||
When a custom `BinaryType` is configured (other than the default `#!cpp std::vector<std::uint8_t>`), you can assign
|
When a custom `BinaryType` is configured (other than the default `#!cpp std::vector<std::uint8_t>`), you can assign
|
||||||
@@ -126,3 +133,6 @@ type `#!cpp binary_t*` must be dereferenced.
|
|||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.8.0. Changed the type of subtype to `std::uint64_t` in version 3.10.0.
|
- Added in version 3.8.0. Changed the type of subtype to `std::uint64_t` in version 3.10.0.
|
||||||
|
- Fixed [`dump`](dump.md), [`std::hash`](std_hash.md), and [`to_ubjson`](to_ubjson.md) for byte types that are not
|
||||||
|
integers (e.g., `#!cpp std::byte`) in version 3.13.0. `dump` now writes the bytes of a signed byte type (e.g.,
|
||||||
|
`#!cpp char`) as 0..255 rather than as negative numbers.
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ literals `#!json true` and `#!json false`.
|
|||||||
|
|
||||||
To store boolean values in C++, a type is defined by the template parameter `BooleanType` which chooses the type to use.
|
To store boolean values in C++, a type is defined by the template parameter `BooleanType` which chooses the type to use.
|
||||||
|
|
||||||
|
## Template parameters
|
||||||
|
|
||||||
|
`BooleanType`
|
||||||
|
: the type to store booleans. As it is stored directly inside a `basic_json` value (in a union), it must be a
|
||||||
|
trivially default-constructible, trivially copyable, and trivially destructible type that is convertible to and
|
||||||
|
from `#!cpp bool`. See
|
||||||
|
[Template Parameter Requirements](../../features/types/template_parameters.md#booleantype).
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
#### Default type
|
#### Default type
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ class basic_json;
|
|||||||
| `BinaryType` | type for binary arrays | [`binary_t`](binary_t.md) |
|
| `BinaryType` | type for binary arrays | [`binary_t`](binary_t.md) |
|
||||||
| `CustomBaseClass` | extension point for user code | [`json_base_class_t`](json_base_class_t.md) |
|
| `CustomBaseClass` | extension point for user code | [`json_base_class_t`](json_base_class_t.md) |
|
||||||
|
|
||||||
|
The library imposes a number of requirements on these types that are not expressed as C++ concepts, such as the
|
||||||
|
container operations `object_t` and `array_t` must provide, or the fact that `StringType` must be `char`-based. They
|
||||||
|
are collected in [Template Parameter Requirements](../../features/types/template_parameters.md).
|
||||||
|
|
||||||
## Specializations
|
## Specializations
|
||||||
|
|
||||||
- [**json**](../json.md) - default specialization
|
- [**json**](../json.md) - default specialization
|
||||||
|
|||||||
@@ -21,8 +21,11 @@ The default value for `CustomBaseClass` is `void`. In this case, an
|
|||||||
|
|
||||||
#### Limitations
|
#### Limitations
|
||||||
|
|
||||||
The type `CustomBaseClass` has to be a default-constructible class.
|
The type `CustomBaseClass` has to be a default-constructible, non-`final` class.
|
||||||
`basic_json` only supports copy/move construction/assignment if `CustomBaseClass` does so as well.
|
`basic_json` only supports copy/move construction/assignment if `CustomBaseClass` does so as well.
|
||||||
|
A `CustomBaseClass` with non-static data members forfeits `basic_json`'s
|
||||||
|
[standard layout](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType) guarantee. See
|
||||||
|
[Template Parameter Requirements](../../features/types/template_parameters.md#custombaseclass).
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ using json_serializer = JSONSerializer<T, SFINAE>;
|
|||||||
|
|
||||||
The default values for `json_serializer` is [`adl_serializer`](../adl_serializer/index.md).
|
The default values for `json_serializer` is [`adl_serializer`](../adl_serializer/index.md).
|
||||||
|
|
||||||
|
#### Requirements
|
||||||
|
|
||||||
|
A custom serializer must provide `#!cpp static void to_json(basic_json&, T)` for every type it serializes, and either
|
||||||
|
`#!cpp static void from_json(const basic_json&, T&)` or `#!cpp static T from_json(const basic_json&)` for every type it
|
||||||
|
deserializes. See [Template Parameter Requirements](../../features/types/template_parameters.md#jsonserializer).
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
??? example
|
??? example
|
||||||
|
|||||||
@@ -20,6 +20,16 @@ used.
|
|||||||
To store floating-point numbers in C++, a type is defined by the template parameter `NumberFloatType` which chooses the
|
To store floating-point numbers in C++, a type is defined by the template parameter `NumberFloatType` which chooses the
|
||||||
type to use.
|
type to use.
|
||||||
|
|
||||||
|
## Template parameters
|
||||||
|
|
||||||
|
`NumberFloatType`
|
||||||
|
: the type to store floating-point numbers. Parsing and serialization are implemented in terms of
|
||||||
|
`#!cpp std::strtof`/`#!cpp std::strtod`/`#!cpp std::strtold` and `#!cpp std::snprintf`, so the type must be
|
||||||
|
`#!cpp float`, `#!cpp double`, or `#!cpp long double`. The
|
||||||
|
[binary formats](../../features/binary_formats/index.md) additionally require `#!cpp float` or `#!cpp double`,
|
||||||
|
because they have no encoding for `#!cpp long double`. See
|
||||||
|
[Template Parameter Requirements](../../features/types/template_parameters.md#numberfloattype).
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
#### Default type
|
#### Default type
|
||||||
|
|||||||
@@ -20,6 +20,13 @@ used.
|
|||||||
To store integer numbers in C++, a type is defined by the template parameter `NumberIntegerType` which chooses the type
|
To store integer numbers in C++, a type is defined by the template parameter `NumberIntegerType` which chooses the type
|
||||||
to use.
|
to use.
|
||||||
|
|
||||||
|
## Template parameters
|
||||||
|
|
||||||
|
`NumberIntegerType`
|
||||||
|
: the type to store signed integers. It must be a **signed integral** type (`#!cpp std::is_integral`) with a
|
||||||
|
`#!cpp std::numeric_limits` specialization, and it is stored directly inside a `basic_json` value. See
|
||||||
|
[Template Parameter Requirements](../../features/types/template_parameters.md#numberintegertype-and-numberunsignedtype).
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
#### Default type
|
#### Default type
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ used.
|
|||||||
To store unsigned integer numbers in C++, a type is defined by the template parameter `NumberUnsignedType` which chooses
|
To store unsigned integer numbers in C++, a type is defined by the template parameter `NumberUnsignedType` which chooses
|
||||||
the type to use.
|
the type to use.
|
||||||
|
|
||||||
|
## Template parameters
|
||||||
|
|
||||||
|
`NumberUnsignedType`
|
||||||
|
: the type to store unsigned integers. It must be an **unsigned integral** type (`#!cpp std::is_integral`) with a
|
||||||
|
`#!cpp std::numeric_limits` specialization, and it must be able to represent the absolute value of every
|
||||||
|
[`number_integer_t`](number_integer_t.md) value. See
|
||||||
|
[Template Parameter Requirements](../../features/types/template_parameters.md#numberintegertype-and-numberunsignedtype).
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
#### Default type
|
#### Default type
|
||||||
|
|||||||
@@ -30,3 +30,5 @@ and [`default_object_comparator_t`](default_object_comparator_t.md) otherwise.
|
|||||||
- Added in version 3.0.0.
|
- Added in version 3.0.0.
|
||||||
- Changed to be conditionally defined as `#!cpp typename object_t::key_compare` or `default_object_comparator_t` in
|
- Changed to be conditionally defined as `#!cpp typename object_t::key_compare` or `default_object_comparator_t` in
|
||||||
version 3.11.0.
|
version 3.11.0.
|
||||||
|
- Fixed the fallback to `default_object_comparator_t`, which previously failed to compile for object types without a
|
||||||
|
`key_compare` member type, in version 3.13.0.
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ To store objects in C++, a type is defined by the template parameters described
|
|||||||
## Template parameters
|
## Template parameters
|
||||||
|
|
||||||
`ObjectType`
|
`ObjectType`
|
||||||
: the container to store objects (e.g., `std::map` or `std::unordered_map`)
|
: the container to store objects. Its template parameters must have the same order and meaning as those of
|
||||||
|
`std::map`; in particular, the third parameter is a comparator. `#!cpp std::unordered_map`, whose third parameter
|
||||||
|
is a hash function, therefore needs an adapter -- see
|
||||||
|
[Template Parameter Requirements](../../features/types/template_parameters.md#objecttype) for the full list of
|
||||||
|
requirements, an adapter example, and the containers that are known to work.
|
||||||
|
|
||||||
`StringType`
|
`StringType`
|
||||||
: the type of the keys or names (e.g., `std::string`). The comparison function `std::less<StringType>` is used to
|
: the type of the keys or names (e.g., `std::string`). The comparison function `std::less<StringType>` is used to
|
||||||
@@ -122,3 +126,4 @@ the object is silently converted as an array of key-value pairs, which is incorr
|
|||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 1.0.0.
|
- Added in version 1.0.0.
|
||||||
|
- Allowed object types whose `erase(iterator)` returns `#!cpp void` in version 3.13.0.
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ JSON class into byte-sized characters during deserialization.
|
|||||||
`StringType`. To work with wide-character data, convert it to/from UTF-8 at the boundary instead -- see the
|
`StringType`. To work with wide-character data, convert it to/from UTF-8 at the boundary instead -- see the
|
||||||
FAQ's [wide string handling](../../home/faq.md#wide-string-handling) section for a conversion recipe.
|
FAQ's [wide string handling](../../home/faq.md#wide-string-handling) section for a conversion recipe.
|
||||||
|
|
||||||
|
Beyond the character type, the library expects a substantial part of the `#!cpp std::string` interface (contiguous
|
||||||
|
null-terminated `data()`, `substr()`, `find()`, `append()`, ...). See
|
||||||
|
[Template Parameter Requirements](../../features/types/template_parameters.md#stringtype) for the full list and
|
||||||
|
for the string types that are known to work.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
#### Default type
|
#### Default type
|
||||||
@@ -78,3 +83,5 @@ and an example.
|
|||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 1.0.0.
|
- Added in version 1.0.0.
|
||||||
|
- Removed the requirement that `string_t` be implicitly convertible from `#!cpp std::string`, which the BSON writer and
|
||||||
|
the UBJSON reader relied on, in version 3.13.0.
|
||||||
|
|||||||
@@ -37,7 +37,14 @@ Linear in the size of the JSON value.
|
|||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
Empty objects and arrays are flattened by [`flatten()`](flatten.md) to `#!json null` values and cannot unflattened to
|
Empty objects and arrays are flattened by [`flatten()`](flatten.md) to `#!json null` values and cannot unflattened to
|
||||||
their original type. Apart from this example, for a JSON value `j`, the following is always true:
|
their original type.
|
||||||
|
|
||||||
|
A flattened array and a flattened object whose keys are array indices are indistinguishable, because both are
|
||||||
|
described by the same JSON pointers. A value is therefore restored as an array if and only if one of its keys is the
|
||||||
|
reference token `0`, and as an object otherwise: `#!json {"2": 1}` is restored unchanged, whereas `#!json {"0": 1}` is
|
||||||
|
restored as `#!json [1]`. This decision does not depend on the order in which the flattened object is iterated.
|
||||||
|
|
||||||
|
Apart from these two cases, for a JSON value `j`, the following is always true:
|
||||||
`#!cpp j == j.flatten().unflatten()`.
|
`#!cpp j == j.flatten().unflatten()`.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
@@ -63,3 +70,4 @@ their original type. Apart from this example, for a JSON value `j`, the followin
|
|||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 2.0.0.
|
- Added in version 2.0.0.
|
||||||
|
- Made the array/object decision independent of the object's iteration order in version 3.13.0.
|
||||||
|
|||||||
@@ -12,9 +12,11 @@
|
|||||||
Controls how exceptions are handled by the library.
|
Controls how exceptions are handled by the library.
|
||||||
|
|
||||||
1. This macro overrides [`#!cpp catch`](https://en.cppreference.com/w/cpp/language/try_catch) calls inside the library.
|
1. This macro overrides [`#!cpp catch`](https://en.cppreference.com/w/cpp/language/try_catch) calls inside the library.
|
||||||
The argument is the type of the exception to catch. As of version 3.8.0, the library only catches `std::out_of_range`
|
The argument is the type of the exception to catch. The library uses it in a single place: to swallow any exception
|
||||||
exceptions internally to rethrow them as [`json::out_of_range`](../../home/exceptions.md#out-of-range) exceptions.
|
escaping the parent-pointer check that [`JSON_DIAGNOSTICS`](json_diagnostics.md) adds to the class invariant. The
|
||||||
The macro is always followed by a scope.
|
places where the library catches its own [`json::out_of_range`](../../home/exceptions.md#out-of-range) exceptions
|
||||||
|
use `JSON_INTERNAL_CATCH` instead, which `JSON_CATCH_USER` also overrides unless `JSON_INTERNAL_CATCH_USER` is
|
||||||
|
defined. The macro is always followed by a scope.
|
||||||
2. This macro overrides `#!cpp throw` calls inside the library. The argument is the exception to be thrown. Note that
|
2. This macro overrides `#!cpp throw` calls inside the library. The argument is the exception to be thrown. Note that
|
||||||
`JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield
|
`JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield
|
||||||
undefined behavior.
|
undefined behavior.
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include "custom_array_type.hpp"
|
||||||
|
|
||||||
|
using custom_json = nlohmann::basic_json<std::map, custom_array_type>;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
custom_json j = custom_json::array();
|
||||||
|
j.push_back(1);
|
||||||
|
j.push_back(2);
|
||||||
|
j.push_back(3);
|
||||||
|
|
||||||
|
std::cout << j.dump() << std::endl;
|
||||||
|
std::cout << std::boolalpha << (custom_json::parse(j.dump()) == j) << std::endl;
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// A minimal, self-contained ArrayType built around a private std::vector.
|
||||||
|
// See https://json.nlohmann.me/features/types/template_parameters/#arraytype
|
||||||
|
template<class T, class Allocator = std::allocator<T>>
|
||||||
|
class custom_array_type
|
||||||
|
{
|
||||||
|
using vector_t = std::vector<T, Allocator>;
|
||||||
|
vector_t data_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = typename vector_t::value_type;
|
||||||
|
using size_type = typename vector_t::size_type;
|
||||||
|
using iterator = typename vector_t::iterator;
|
||||||
|
using const_iterator = typename vector_t::const_iterator;
|
||||||
|
|
||||||
|
custom_array_type() = default;
|
||||||
|
custom_array_type(const custom_array_type&) = default;
|
||||||
|
custom_array_type(custom_array_type&&) = default;
|
||||||
|
custom_array_type& operator=(const custom_array_type&) = default;
|
||||||
|
custom_array_type& operator=(custom_array_type&&) = default;
|
||||||
|
|
||||||
|
template<class InputIt>
|
||||||
|
custom_array_type(InputIt first, InputIt last) : data_(first, last) {}
|
||||||
|
|
||||||
|
custom_array_type(size_type count, const T& value) : data_(count, value) {}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return data_.begin();
|
||||||
|
}
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return data_.end();
|
||||||
|
}
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return data_.begin();
|
||||||
|
}
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return data_.end();
|
||||||
|
}
|
||||||
|
const_iterator cbegin() const
|
||||||
|
{
|
||||||
|
return data_.cbegin();
|
||||||
|
}
|
||||||
|
const_iterator cend() const
|
||||||
|
{
|
||||||
|
return data_.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return data_.empty();
|
||||||
|
}
|
||||||
|
size_type size() const
|
||||||
|
{
|
||||||
|
return data_.size();
|
||||||
|
}
|
||||||
|
size_type max_size() const
|
||||||
|
{
|
||||||
|
return data_.max_size();
|
||||||
|
}
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
data_.clear();
|
||||||
|
}
|
||||||
|
void resize(size_type n)
|
||||||
|
{
|
||||||
|
data_.resize(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator[](size_type pos)
|
||||||
|
{
|
||||||
|
return data_[pos];
|
||||||
|
}
|
||||||
|
const T& operator[](size_type pos) const
|
||||||
|
{
|
||||||
|
return data_[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
T& back()
|
||||||
|
{
|
||||||
|
return data_.back();
|
||||||
|
}
|
||||||
|
const T& back() const
|
||||||
|
{
|
||||||
|
return data_.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(const T& value)
|
||||||
|
{
|
||||||
|
data_.push_back(value);
|
||||||
|
}
|
||||||
|
void push_back(T&& value)
|
||||||
|
{
|
||||||
|
data_.push_back(std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
void emplace_back(Args&& ... args)
|
||||||
|
{
|
||||||
|
data_.emplace_back(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
data_.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert(const_iterator pos, const T& value)
|
||||||
|
{
|
||||||
|
return data_.insert(pos, value);
|
||||||
|
}
|
||||||
|
iterator insert(const_iterator pos, size_type count, const T& value)
|
||||||
|
{
|
||||||
|
return data_.insert(pos, count, value);
|
||||||
|
}
|
||||||
|
template<class InputIt>
|
||||||
|
iterator insert(const_iterator pos, InputIt first, InputIt last)
|
||||||
|
{
|
||||||
|
return data_.insert(pos, first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(const_iterator pos)
|
||||||
|
{
|
||||||
|
return data_.erase(pos);
|
||||||
|
}
|
||||||
|
iterator erase(const_iterator first, const_iterator last)
|
||||||
|
{
|
||||||
|
return data_.erase(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(custom_array_type& other)
|
||||||
|
{
|
||||||
|
data_.swap(other.data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const custom_array_type& lhs, const custom_array_type& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data_ == rhs.data_;
|
||||||
|
}
|
||||||
|
friend bool operator<(const custom_array_type& lhs, const custom_array_type& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data_ < rhs.data_;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[1,2,3]
|
||||||
|
true
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include "custom_binary_type.hpp"
|
||||||
|
|
||||||
|
using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool,
|
||||||
|
std::int64_t, std::uint64_t, double, std::allocator,
|
||||||
|
nlohmann::adl_serializer, custom_binary_type>;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const auto j = custom_json::binary({0x01, 0x02, 0x03});
|
||||||
|
|
||||||
|
std::cout << j.dump() << std::endl;
|
||||||
|
std::cout << std::boolalpha << (custom_json::from_cbor(custom_json::to_cbor(j)) == j) << std::endl;
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// A minimal, self-contained BinaryType built around a private std::vector.
|
||||||
|
// See https://json.nlohmann.me/features/types/template_parameters/#binarytype
|
||||||
|
class custom_binary_type
|
||||||
|
{
|
||||||
|
using vector_t = std::vector<std::uint8_t>;
|
||||||
|
vector_t data_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = vector_t::value_type;
|
||||||
|
using size_type = vector_t::size_type;
|
||||||
|
using iterator = vector_t::iterator;
|
||||||
|
using const_iterator = vector_t::const_iterator;
|
||||||
|
|
||||||
|
custom_binary_type() = default;
|
||||||
|
custom_binary_type(const custom_binary_type&) = default;
|
||||||
|
custom_binary_type(custom_binary_type&&) = default;
|
||||||
|
custom_binary_type& operator=(const custom_binary_type&) = default;
|
||||||
|
custom_binary_type& operator=(custom_binary_type&&) = default;
|
||||||
|
|
||||||
|
template<class InputIt>
|
||||||
|
custom_binary_type(InputIt first, InputIt last) : data_(first, last) {}
|
||||||
|
|
||||||
|
// so basic_json::binary({0x01, 0x02}) can build one directly
|
||||||
|
custom_binary_type(std::initializer_list<std::uint8_t> init) : data_(init) {}
|
||||||
|
|
||||||
|
size_type size() const
|
||||||
|
{
|
||||||
|
return data_.size();
|
||||||
|
}
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return data_.empty();
|
||||||
|
}
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
data_.clear();
|
||||||
|
}
|
||||||
|
void resize(size_type n)
|
||||||
|
{
|
||||||
|
data_.resize(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read-only is enough: the writers only ever read from a binary value
|
||||||
|
const std::uint8_t* data() const
|
||||||
|
{
|
||||||
|
return data_.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint8_t& operator[](size_type pos)
|
||||||
|
{
|
||||||
|
return data_[pos];
|
||||||
|
}
|
||||||
|
std::uint8_t operator[](size_type pos) const
|
||||||
|
{
|
||||||
|
return data_[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint8_t& back()
|
||||||
|
{
|
||||||
|
return data_.back();
|
||||||
|
}
|
||||||
|
std::uint8_t back() const
|
||||||
|
{
|
||||||
|
return data_.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return data_.begin();
|
||||||
|
}
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return data_.end();
|
||||||
|
}
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return data_.begin();
|
||||||
|
}
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return data_.end();
|
||||||
|
}
|
||||||
|
const_iterator cbegin() const
|
||||||
|
{
|
||||||
|
return data_.cbegin();
|
||||||
|
}
|
||||||
|
const_iterator cend() const
|
||||||
|
{
|
||||||
|
return data_.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class InputIt>
|
||||||
|
iterator insert(const_iterator pos, InputIt first, InputIt last)
|
||||||
|
{
|
||||||
|
return data_.insert(pos, first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const custom_binary_type& lhs, const custom_binary_type& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data_ == rhs.data_;
|
||||||
|
}
|
||||||
|
friend bool operator<(const custom_binary_type& lhs, const custom_binary_type& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data_ < rhs.data_;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
{"bytes":[1,2,3],"subtype":null}
|
||||||
|
true
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include "custom_object_type.hpp"
|
||||||
|
|
||||||
|
using custom_json = nlohmann::basic_json<custom_object_type, std::vector>;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
custom_json j;
|
||||||
|
j["pi"] = 3.141;
|
||||||
|
j["happy"] = true;
|
||||||
|
j["list"] = {1, 2, 3};
|
||||||
|
|
||||||
|
std::cout << j.dump(2) << std::endl;
|
||||||
|
std::cout << std::boolalpha << (custom_json::parse(j.dump()) == j) << std::endl;
|
||||||
|
|
||||||
|
// custom_object_type has no key_compare member, so object_comparator_t
|
||||||
|
// falls back to its default
|
||||||
|
std::cout << std::boolalpha
|
||||||
|
<< std::is_same<custom_json::object_comparator_t, custom_json::default_object_comparator_t>::value
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
// A minimal, self-contained ObjectType built around a private std::map.
|
||||||
|
// key_compare is deliberately not exposed: when an ObjectType has no
|
||||||
|
// key_compare member, the library falls back to its own default comparator.
|
||||||
|
// See https://json.nlohmann.me/features/types/template_parameters/#objecttype
|
||||||
|
template<class Key, class T, class Compare, class Allocator>
|
||||||
|
class custom_object_type
|
||||||
|
{
|
||||||
|
using map_t = std::map<Key, T, Compare, Allocator>;
|
||||||
|
map_t data_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type = typename map_t::key_type;
|
||||||
|
using mapped_type = typename map_t::mapped_type;
|
||||||
|
using value_type = typename map_t::value_type;
|
||||||
|
using size_type = typename map_t::size_type;
|
||||||
|
using iterator = typename map_t::iterator;
|
||||||
|
using const_iterator = typename map_t::const_iterator;
|
||||||
|
|
||||||
|
custom_object_type() = default;
|
||||||
|
custom_object_type(const custom_object_type&) = default;
|
||||||
|
custom_object_type(custom_object_type&&) = default;
|
||||||
|
custom_object_type& operator=(const custom_object_type&) = default;
|
||||||
|
custom_object_type& operator=(custom_object_type&&) = default;
|
||||||
|
|
||||||
|
template<class InputIt>
|
||||||
|
custom_object_type(InputIt first, InputIt last) : data_(first, last) {}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return data_.begin();
|
||||||
|
}
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return data_.end();
|
||||||
|
}
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return data_.begin();
|
||||||
|
}
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return data_.end();
|
||||||
|
}
|
||||||
|
const_iterator cbegin() const
|
||||||
|
{
|
||||||
|
return data_.cbegin();
|
||||||
|
}
|
||||||
|
const_iterator cend() const
|
||||||
|
{
|
||||||
|
return data_.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return data_.empty();
|
||||||
|
}
|
||||||
|
size_type size() const
|
||||||
|
{
|
||||||
|
return data_.size();
|
||||||
|
}
|
||||||
|
size_type max_size() const
|
||||||
|
{
|
||||||
|
return data_.max_size();
|
||||||
|
}
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
data_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find(const key_type& key)
|
||||||
|
{
|
||||||
|
return data_.find(key);
|
||||||
|
}
|
||||||
|
const_iterator find(const key_type& key) const
|
||||||
|
{
|
||||||
|
return data_.find(key);
|
||||||
|
}
|
||||||
|
size_type count(const key_type& key) const
|
||||||
|
{
|
||||||
|
return data_.count(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> emplace(const key_type& key, const mapped_type& value)
|
||||||
|
{
|
||||||
|
return data_.emplace(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> insert(const value_type& value)
|
||||||
|
{
|
||||||
|
return data_.insert(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class InputIt>
|
||||||
|
void insert(InputIt first, InputIt last)
|
||||||
|
{
|
||||||
|
data_.insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_type& operator[](const key_type& key)
|
||||||
|
{
|
||||||
|
return data_[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_type& at(const key_type& key)
|
||||||
|
{
|
||||||
|
return data_.at(key);
|
||||||
|
}
|
||||||
|
const mapped_type& at(const key_type& key) const
|
||||||
|
{
|
||||||
|
return data_.at(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(iterator pos)
|
||||||
|
{
|
||||||
|
return data_.erase(pos);
|
||||||
|
}
|
||||||
|
iterator erase(iterator first, iterator last)
|
||||||
|
{
|
||||||
|
return data_.erase(first, last);
|
||||||
|
}
|
||||||
|
size_type erase(const key_type& key)
|
||||||
|
{
|
||||||
|
return data_.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(custom_object_type& other)
|
||||||
|
{
|
||||||
|
data_.swap(other.data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const custom_object_type& lhs, const custom_object_type& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data_ == rhs.data_;
|
||||||
|
}
|
||||||
|
friend bool operator<(const custom_object_type& lhs, const custom_object_type& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data_ < rhs.data_;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"happy": true,
|
||||||
|
"list": [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"pi": 3.141
|
||||||
|
}
|
||||||
|
true
|
||||||
|
true
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include "custom_string_type.hpp"
|
||||||
|
|
||||||
|
using custom_json = nlohmann::basic_json<std::map, std::vector, custom_string_type>;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
custom_json j;
|
||||||
|
j["pi"] = 3.141;
|
||||||
|
j["happy"] = true;
|
||||||
|
j["list"] = {1, 2, 3};
|
||||||
|
|
||||||
|
std::cout << j.dump(2) << std::endl;
|
||||||
|
std::cout << std::boolalpha << (custom_json::parse(j.dump()) == j) << std::endl;
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// A minimal, self-contained StringType built around a private std::string.
|
||||||
|
// Wraps rather than inherits, so it exposes exactly what the library needs
|
||||||
|
// and nothing more of std::string's interface.
|
||||||
|
//
|
||||||
|
// Covers the "Always required" members, the extras needed for the binary
|
||||||
|
// formats, and the extras needed for JSON Pointer / flatten / unflatten /
|
||||||
|
// diff. Extending it further (e.g. for std::hash<basic_json> or to_bson) is
|
||||||
|
// a matter of adding the extra members listed in the "Required for other
|
||||||
|
// functionality" table.
|
||||||
|
//
|
||||||
|
// See https://json.nlohmann.me/features/types/template_parameters/#stringtype
|
||||||
|
class custom_string_type
|
||||||
|
{
|
||||||
|
std::string data_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = char;
|
||||||
|
using size_type = std::string::size_type;
|
||||||
|
using iterator = std::string::iterator;
|
||||||
|
using const_iterator = std::string::const_iterator;
|
||||||
|
|
||||||
|
static constexpr size_type npos = std::string::npos;
|
||||||
|
|
||||||
|
custom_string_type() = default;
|
||||||
|
custom_string_type(const custom_string_type&) = default;
|
||||||
|
custom_string_type(custom_string_type&&) = default;
|
||||||
|
custom_string_type& operator=(const custom_string_type&) = default;
|
||||||
|
custom_string_type& operator=(custom_string_type&&) = default;
|
||||||
|
|
||||||
|
// not explicit: the library relies on being able to hand it a string literal
|
||||||
|
custom_string_type(const char* s) : data_(s) {}
|
||||||
|
custom_string_type(const char* s, size_type count) : data_(s, count) {}
|
||||||
|
custom_string_type(size_type count, char ch) : data_(count, ch) {}
|
||||||
|
|
||||||
|
size_type size() const
|
||||||
|
{
|
||||||
|
return data_.size();
|
||||||
|
}
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return data_.empty();
|
||||||
|
}
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
data_.clear();
|
||||||
|
}
|
||||||
|
void resize(size_type n)
|
||||||
|
{
|
||||||
|
data_.resize(n);
|
||||||
|
}
|
||||||
|
void resize(size_type n, char c)
|
||||||
|
{
|
||||||
|
data_.resize(n, c);
|
||||||
|
}
|
||||||
|
void reserve(size_type n)
|
||||||
|
{
|
||||||
|
data_.reserve(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// must stay null-terminated -- the parser hands this to std::strtoull &
|
||||||
|
// friends; std::string::data() has guaranteed that since C++11
|
||||||
|
const char* data() const
|
||||||
|
{
|
||||||
|
return data_.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(char c)
|
||||||
|
{
|
||||||
|
data_.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
char& operator[](size_type pos)
|
||||||
|
{
|
||||||
|
return data_[pos];
|
||||||
|
}
|
||||||
|
char operator[](size_type pos) const
|
||||||
|
{
|
||||||
|
return data_[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
custom_string_type& append(const char* s, size_type count)
|
||||||
|
{
|
||||||
|
data_.append(s, count);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
custom_string_type& append(const custom_string_type& other)
|
||||||
|
{
|
||||||
|
data_.append(other.data_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type find_first_of(char c, size_type pos = 0) const
|
||||||
|
{
|
||||||
|
return data_.find_first_of(c, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return data_.begin();
|
||||||
|
}
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return data_.end();
|
||||||
|
}
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return data_.begin();
|
||||||
|
}
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return data_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const custom_string_type& lhs, const custom_string_type& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data_ == rhs.data_;
|
||||||
|
}
|
||||||
|
friend bool operator<(const custom_string_type& lhs, const custom_string_type& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data_ < rhs.data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not required by the library itself, but dump() returns a custom_string_type
|
||||||
|
// and this makes `std::cout << j.dump()` work as expected
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const custom_string_type& s)
|
||||||
|
{
|
||||||
|
return os << s.data_;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"happy": true,
|
||||||
|
"list": [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"pi": 3.141
|
||||||
|
}
|
||||||
|
true
|
||||||
@@ -51,7 +51,11 @@ If you do want to preserve the **insertion order**, you can use the type [`nlohm
|
|||||||
--8<-- "examples/ordered_json.output"
|
--8<-- "examples/ordered_json.output"
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).
|
Alternatively, [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) also preserves the insertion order and, unlike [`ordered_map`](../api/ordered_map.md), keeps a lookup index, so it does not have the quadratic cost described below. It is used through a small adapter ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).
|
||||||
|
|
||||||
|
If the order does not matter and you only want faster lookup, `boost::unordered_flat_map`, `absl::flat_hash_map`, `absl::node_hash_map`, and several other hash maps work through an adapter that restores the template argument order `basic_json` expects; see [Template Parameter Requirements](types/template_parameters.md#objecttype). Note these are *unordered*, not insertion-ordered.
|
||||||
|
|
||||||
|
[`tsl::ordered_map`](https://github.com/Tessil/ordered-map) cannot be used: its iterators expose the mapped value as `const`, while `basic_json` needs to modify it in place.
|
||||||
|
|
||||||
The [`ordered_map`](../api/ordered_map.md) behind `nlohmann::ordered_json` is deliberately minimal and has no lookup
|
The [`ordered_map`](../api/ordered_map.md) behind `nlohmann::ordered_json` is deliberately minimal and has no lookup
|
||||||
index, so every key access is a linear scan and building an object of `n` keys costs O(n²). This is unnoticeable at
|
index, so every key access is a linear scan and building an object of `n` keys costs O(n²). This is unnoticeable at
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ template<
|
|||||||
class NumberFloatType = double,
|
class NumberFloatType = double,
|
||||||
template<typename U> class AllocatorType = std::allocator,
|
template<typename U> class AllocatorType = std::allocator,
|
||||||
template<typename T, typename SFINAE = void> class JSONSerializer = adl_serializer,
|
template<typename T, typename SFINAE = void> class JSONSerializer = adl_serializer,
|
||||||
class BinaryType = std::vector<std::uint8_t>
|
class BinaryType = std::vector<std::uint8_t>,
|
||||||
|
class CustomBaseClass = void
|
||||||
>
|
>
|
||||||
class basic_json;
|
class basic_json;
|
||||||
```
|
```
|
||||||
@@ -106,6 +107,10 @@ using number_float_t = NumberFloatType;
|
|||||||
using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
|
using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Not every type can be passed for these template arguments: the library uses the resulting types in ways that imply a
|
||||||
|
number of requirements, for instance that `StringType` is `char`-based or that `ArrayType` is vector-like. These
|
||||||
|
requirements are collected in [Template Parameter Requirements](template_parameters.md).
|
||||||
|
|
||||||
|
|
||||||
## Objects
|
## Objects
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,747 @@
|
|||||||
|
# Template Parameter Requirements
|
||||||
|
|
||||||
|
Class [`basic_json`](../../api/basic_json/index.md) is configurable through eleven template parameters. The library
|
||||||
|
never formally states what a type passed for one of these parameters has to provide -- the requirements are implied by
|
||||||
|
the way the library uses the resulting [`object_t`](../../api/basic_json/object_t.md),
|
||||||
|
[`array_t`](../../api/basic_json/array_t.md), [`string_t`](../../api/basic_json/string_t.md), etc. This page collects
|
||||||
|
these requirements so they do not have to be discovered by trial and error. Each section lists the concrete types
|
||||||
|
that are known to work for that parameter and the ones that do not, checked against Boost 1.83, Abseil 20250127.0,
|
||||||
|
Folly, EASTL 3.21, `ankerl::unordered_dense`, `phmap`, `gtl`, `robin_hood`, `tsl::ordered_map`, and Qt 6.
|
||||||
|
|
||||||
|
## How to read this page
|
||||||
|
|
||||||
|
Requirements are split into two groups:
|
||||||
|
|
||||||
|
- **Always required** -- needed to instantiate `basic_json` at all, or needed by functions that virtually every program
|
||||||
|
uses (construction, element access, [`dump`](../../api/basic_json/dump.md)).
|
||||||
|
- **Required for ...** -- only needed when a particular part of the API is instantiated. Member function templates are
|
||||||
|
only instantiated when they are used, so a type may be perfectly usable even though it does not satisfy these
|
||||||
|
requirements, as long as the corresponding functions are never called.
|
||||||
|
|
||||||
|
!!! warning "Requirements are not checked"
|
||||||
|
|
||||||
|
Three requirements are checked with a `#!cpp static_assert`: the array iterator category, the width of
|
||||||
|
[`BinaryType`](#binarytype)'s `value_type`, and [`NumberUnsignedType`](#numberintegertype-and-numberunsignedtype)
|
||||||
|
being at least as wide as [`NumberIntegerType`](#numberintegertype-and-numberunsignedtype). The rest are not
|
||||||
|
diagnosed with dedicated error messages, and violating most of them results in a compiler error somewhere inside
|
||||||
|
the library. Four violations are not caught at compile time at all:
|
||||||
|
|
||||||
|
- A [`StringType`](#stringtype) whose `data()` is not null-terminated compiles and silently misparses numbers,
|
||||||
|
because the lexer hands the buffer to `#!cpp std::strtoull`/`#!cpp std::strtoll`/`#!cpp std::strtod`.
|
||||||
|
- A stateful [`AllocatorType`](#allocatortype) compiles and silently ignores its state: allocation, deallocation,
|
||||||
|
and [`get_allocator()`](../../api/basic_json/get_allocator.md) each use a different default-constructed instance.
|
||||||
|
- The two [cross-specialization conversions](#cross-specialization-conversions) below. These abort on an assertion
|
||||||
|
in a normal build, and only fail silently under `#!cpp NDEBUG`.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
| Template parameter | Default | Notable substitutes |
|
||||||
|
|-------------------------------------------------------------------|-----------------------------------|-----------------------------------------------------------------------|
|
||||||
|
| [`ObjectType`](#objecttype) | `std::map` | [`nlohmann::ordered_map`](../../api/ordered_map.md), Abseil hash maps |
|
||||||
|
| [`ArrayType`](#arraytype) | `std::vector` | `#!cpp std::deque` |
|
||||||
|
| [`StringType`](#stringtype) | `std::string` | `std::string`-like types over `char` |
|
||||||
|
| [`BooleanType`](#booleantype) | `bool` | none worth using |
|
||||||
|
| [`NumberIntegerType`](#numberintegertype-and-numberunsignedtype) | `std::int64_t` | any signed integer type |
|
||||||
|
| [`NumberUnsignedType`](#numberintegertype-and-numberunsignedtype) | `std::uint64_t` | any unsigned integer type at least as wide as `NumberIntegerType` |
|
||||||
|
| [`NumberFloatType`](#numberfloattype) | `double` | `float` (`long double`: no binary formats) |
|
||||||
|
| [`AllocatorType`](#allocatortype) | `std::allocator` | stateless allocators |
|
||||||
|
| [`JSONSerializer`](#jsonserializer) | `adl_serializer` | serializers with the same interface |
|
||||||
|
| [`BinaryType`](#binarytype) | `#!cpp std::vector<std::uint8_t>` | `#!cpp std::vector<char>` |
|
||||||
|
| [`CustomBaseClass`](#custombaseclass) | `void` | any default-constructible class |
|
||||||
|
|
||||||
|
!!! warning "Third-party containers and incomplete types"
|
||||||
|
|
||||||
|
`object_t` is instantiated inside the definition of `basic_json` -- it is probed for a `key_compare` member to
|
||||||
|
form [`object_comparator_t`](../../api/basic_json/object_comparator_t.md) -- i.e. while `basic_json` is still an
|
||||||
|
incomplete type. `#!cpp std::map` is required by the standard to support incomplete mapped types; most
|
||||||
|
third-party maps are not, and inspecting the mapped type at class scope (for instance with
|
||||||
|
`#!cpp std::is_trivially_move_assignable`) makes them unusable as `ObjectType`, no matter how their template
|
||||||
|
arguments are adapted. This rules out `absl::btree_map`, `phmap::btree_map`, `gtl::btree_map`,
|
||||||
|
`robin_hood::unordered_node_map`, `folly::F14FastMap`, and `eastl::hash_map`.
|
||||||
|
|
||||||
|
`array_t` is only *named* in the class definition and is not instantiated until `basic_json` is complete, so an
|
||||||
|
`ArrayType` that inspects its value type at class scope is generally fine -- `boost::container::small_vector` and
|
||||||
|
`static_vector` both reject incomplete value types yet work here. `absl::InlinedVector` is the exception: the
|
||||||
|
`#!cpp std::is_trivially_move_assignable<basic_json>` it evaluates while instantiating itself re-enters the
|
||||||
|
library's own trait machinery mid-instantiation.
|
||||||
|
|
||||||
|
!!! note "Folly requires C++20"
|
||||||
|
|
||||||
|
Folly's headers use `#!cpp consteval` and `#!cpp std::type_identity`, so any `basic_json` specialization that
|
||||||
|
names a Folly type has to be compiled as C++20 or later, whatever the rest of the library supports.
|
||||||
|
|
||||||
|
## `ObjectType`
|
||||||
|
|
||||||
|
`ObjectType` is instantiated as
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using object_t = ObjectType<StringType, // key_type
|
||||||
|
basic_json, // mapped_type
|
||||||
|
default_object_comparator_t, // key_compare
|
||||||
|
AllocatorType<std::pair<const StringType,
|
||||||
|
basic_json>>>; // allocator_type
|
||||||
|
```
|
||||||
|
|
||||||
|
i.e., the template arguments follow the order and meaning of `std::map`.
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- The template must be usable with **four** type arguments in the order shown above. The third argument is a
|
||||||
|
**comparator**; containers that expect something else in this position (e.g., a hash function) need an alias template
|
||||||
|
or wrapper -- see [Notes](#notes).
|
||||||
|
- An optional member type `key_compare`. If it is present it becomes
|
||||||
|
[`object_comparator_t`](../../api/basic_json/object_comparator_t.md); otherwise
|
||||||
|
[`default_object_comparator_t`](../../api/basic_json/default_object_comparator_t.md) is used.
|
||||||
|
- Member types `key_type`, `mapped_type`, `value_type`, and `iterator`.
|
||||||
|
- `value_type` must behave like `#!cpp std::pair<const key_type, mapped_type>`; the library accesses `.first` and
|
||||||
|
`.second` on it.
|
||||||
|
- `iterator` must be default-constructible and satisfy
|
||||||
|
[LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator). The type returned
|
||||||
|
by `cbegin()`/`cend()` must satisfy the same requirements.
|
||||||
|
- Constructors: default, copy, move, and from an iterator range `(first, last)`.
|
||||||
|
- Member functions `begin()`, `end()`, `cbegin()`, `cend()`, `empty()`, `size()`, `max_size()`, `clear()`,
|
||||||
|
`find(key)`, `count(key)`, `emplace(key, value)`, `insert(value_type)`, `insert(first, last)`, `operator[](key)`,
|
||||||
|
`erase(iterator)`, and `erase(first, last)`. `erase(iterator)` may return the following iterator or `#!cpp void`;
|
||||||
|
in the latter case the library computes the successor itself, before erasing.
|
||||||
|
- `erase(key)` is **optional**: if the container does not provide one, the library falls back to `find(key)` followed
|
||||||
|
by `erase(iterator)`.
|
||||||
|
- `at(key)` is required only by [`to_ubjson`](../../api/basic_json/to_ubjson.md) and
|
||||||
|
[`to_bjdata`](../../api/basic_json/to_bjdata.md), but every container tried here provides it.
|
||||||
|
- `emplace` and `insert(value_type)` must return `#!cpp std::pair<iterator, bool>` and must have **unique-key**
|
||||||
|
semantics; multimaps cannot be used.
|
||||||
|
- The type must be swappable (via `std::swap` or an ADL `swap`).
|
||||||
|
- The comparison operators `==` and `<`; `!=`, `<=`, `>`, and `>=` are derived from them. Where the library uses
|
||||||
|
three-way comparison (C++20), `==` and `<=>` are required **instead** -- the six two-way operators do not satisfy
|
||||||
|
it. They implement [`basic_json`'s comparison operators](../../api/basic_json/operator_eq.md).
|
||||||
|
|
||||||
|
### Required for heterogeneous key lookup
|
||||||
|
|
||||||
|
The overloads of [`at`](../../api/basic_json/at.md), [`operator[]`](../../api/basic_json/operator%5B%5D.md),
|
||||||
|
[`find`](../../api/basic_json/find.md), [`contains`](../../api/basic_json/contains.md),
|
||||||
|
[`count`](../../api/basic_json/count.md), [`erase`](../../api/basic_json/erase.md), and
|
||||||
|
[`value`](../../api/basic_json/value.md) that accept a key type other than `object_t::key_type` require
|
||||||
|
|
||||||
|
- a **transparent** comparator, i.e. [`object_comparator_t`](../../api/basic_json/object_comparator_t.md) has a member
|
||||||
|
type `is_transparent` (this is why the default comparator is `#!cpp std::less<>` since C++14), and
|
||||||
|
- corresponding heterogeneous `find`, `count`, `erase`, and `operator[]` overloads on the container.
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
#### `std::unordered_map` needs an adapter
|
||||||
|
|
||||||
|
`#!cpp std::unordered_map` cannot be passed directly: its third template parameter is a hash function, but
|
||||||
|
`basic_json` passes a comparator in that position. An alias template or wrapper that restores the expected argument
|
||||||
|
order makes it usable:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<class Key, class T, class IgnoredCompare, class Allocator>
|
||||||
|
struct unordered_map_object
|
||||||
|
: std::unordered_map<Key, T, std::hash<Key>, std::equal_to<Key>, Allocator>
|
||||||
|
{
|
||||||
|
using base_t = std::unordered_map<Key, T, std::hash<Key>, std::equal_to<Key>, Allocator>;
|
||||||
|
using base_t::base_t;
|
||||||
|
};
|
||||||
|
|
||||||
|
using unordered_json = nlohmann::basic_json<unordered_map_object>;
|
||||||
|
```
|
||||||
|
|
||||||
|
Whether `#!cpp std::unordered_map` can be instantiated at all depends on the standard library: `object_t` is formed
|
||||||
|
while `basic_json` is still incomplete (see the warning above), and libstdc++ 9 needs the size of the mapped type to
|
||||||
|
instantiate the hash map's node type, so the adapter does not compile there. Newer libstdc++ versions, and the hash
|
||||||
|
maps listed below, do not have that problem.
|
||||||
|
|
||||||
|
The adapter above works verbatim for Abseil's, Boost's, `phmap`'s and `gtl`'s hash maps, which all place the hash
|
||||||
|
function third and take a `#!cpp std::pair<const Key, T>` allocator fifth. Two need a different adapter:
|
||||||
|
|
||||||
|
- `ankerl::unordered_dense` expects an allocator over `#!cpp std::pair<Key, T>` (non-const key), so the allocator has
|
||||||
|
to be rebound to that or dropped.
|
||||||
|
- `robin_hood`'s fifth parameter is the non-type `MaxLoadFactor100`, so its adapter must drop the allocator entirely.
|
||||||
|
|
||||||
|
None of these hash maps defines `key_compare`, so all of them additionally rely on `object_comparator_t` falling back
|
||||||
|
to [`default_object_comparator_t`](../../api/basic_json/default_object_comparator_t.md); see
|
||||||
|
[`object_comparator_t`](../../api/basic_json/object_comparator_t.md).
|
||||||
|
|
||||||
|
#### Abseil hash maps
|
||||||
|
|
||||||
|
`absl::flat_hash_map` and `absl::node_hash_map` tolerate an incomplete value type, but they take a hash function as
|
||||||
|
their third template argument. The same adapter as for `#!cpp std::unordered_map` makes them usable:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<class Key, class T, class IgnoredCompare, class Allocator>
|
||||||
|
struct flat_hash_object
|
||||||
|
: absl::flat_hash_map<Key, T, absl::Hash<Key>, std::equal_to<Key>, Allocator>
|
||||||
|
{
|
||||||
|
using base_t = absl::flat_hash_map<Key, T, absl::Hash<Key>, std::equal_to<Key>, Allocator>;
|
||||||
|
using base_t::base_t;
|
||||||
|
};
|
||||||
|
|
||||||
|
using flat_hash_json = nlohmann::basic_json<flat_hash_object>;
|
||||||
|
```
|
||||||
|
|
||||||
|
`absl::node_hash_map` keeps references to the mapped values valid across insertions; `absl::flat_hash_map` does not,
|
||||||
|
which makes it behave like [`ordered_json`](../../api/ordered_json.md) with respect to
|
||||||
|
[iterator invalidation](../../api/basic_json/index.md#iterator-invalidation). Both expose a `capacity()` member
|
||||||
|
function, so [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md) treats them conservatively and keeps the
|
||||||
|
parent pointers correct either way.
|
||||||
|
|
||||||
|
#### Iteration order
|
||||||
|
|
||||||
|
The library never relies on the container's iteration order for correctness; it does determine the order in which
|
||||||
|
object keys are serialized by [`dump`](../../api/basic_json/dump.md) and visited by
|
||||||
|
[`items`](../../api/basic_json/items.md). See [Object Order](../object_order.md).
|
||||||
|
|
||||||
|
#### `capacity()` marks a container as insertion-ordered
|
||||||
|
|
||||||
|
With [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md) enabled, the library detects insertion-ordered maps by
|
||||||
|
probing for a `capacity()` member function (`nlohmann::ordered_map` inherits it from `std::vector`) and refreshes all
|
||||||
|
parent pointers after every insertion. An `ObjectType` that happens to have a `capacity()` member is therefore treated
|
||||||
|
conservatively -- this is correct, but slower.
|
||||||
|
|
||||||
|
#### Key order and duplicate keys
|
||||||
|
|
||||||
|
The library does not sort or de-duplicate keys itself; the behavior described in
|
||||||
|
[`object_t`](../../api/basic_json/object_t.md) is entirely the behavior of the chosen container.
|
||||||
|
|
||||||
|
!!! tip "Reference implementation"
|
||||||
|
|
||||||
|
`docs/mkdocs/docs/examples/custom_object_type.hpp` wraps a private `#!cpp std::map` and satisfies every
|
||||||
|
requirement above. It does not define `key_compare`, so `object_comparator_t` falls back to
|
||||||
|
[`default_object_comparator_t`](../../api/basic_json/default_object_comparator_t.md) -- a good starting point for
|
||||||
|
a custom `ObjectType`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/custom_object_type.hpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Compiling and using it"
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/custom_object_type.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/custom_object_type.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compatible containers
|
||||||
|
|
||||||
|
| Container | Notes |
|
||||||
|
|----------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
|
||||||
|
| `#!cpp std::map` (default) | |
|
||||||
|
| [`nlohmann::ordered_map`](../../api/ordered_map.md) | used by [`ordered_json`](../../api/ordered_json.md); keeps insertion order |
|
||||||
|
| [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) | keeps insertion order; adapter puts `fifo_map_compare` in the comparator slot |
|
||||||
|
| `boost::container::map`, `boost::container::flat_map` | no adapter needed |
|
||||||
|
| `#!cpp std::unordered_map` | through the adapter above; not with libstdc++ 9, see the note |
|
||||||
|
| `boost::unordered_map`, `boost::unordered_flat_map`, `boost::unordered_node_map` | through the adapter above |
|
||||||
|
| `absl::flat_hash_map`, `absl::node_hash_map` | through the adapter above; `flat_hash_map` moves mapped values on rehash |
|
||||||
|
| `phmap::flat_hash_map`, `phmap::node_hash_map`, `gtl::flat_hash_map` | through the adapter above |
|
||||||
|
| `ankerl::unordered_dense::map` and `segmented_map` | adapter must rebind or drop the allocator |
|
||||||
|
| `robin_hood::unordered_flat_map` | adapter must drop the allocator |
|
||||||
|
| `folly::F14NodeMap` | through the adapter above; requires C++20, see the note above |
|
||||||
|
| `folly::sorted_vector_map` | alias must drop the allocator, whose value type it disagrees on |
|
||||||
|
|
||||||
|
### Containers that cannot be used
|
||||||
|
|
||||||
|
| Container | Reason |
|
||||||
|
|--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `absl::btree_map`, `phmap::btree_map`, `gtl::btree_map` | require a complete mapped type |
|
||||||
|
| `robin_hood::unordered_node_map`, `folly::F14FastMap`, `eastl::hash_map` | require a complete mapped type |
|
||||||
|
| `eastl::map` | EASTL iterators do not work with `#!cpp std::iterator_traits` |
|
||||||
|
| `tsl::ordered_map` | its iterators expose the mapped value as `#!cpp const` |
|
||||||
|
| `QMap` | no `value_type` member type |
|
||||||
|
| `QHash` | its `value_type` is the mapped type rather than a key/value pair, and its iterators dereference to the mapped value |
|
||||||
|
| `#!cpp std::multimap`, `#!cpp std::unordered_multimap` | `emplace` does not return `#!cpp std::pair<iterator, bool>` |
|
||||||
|
|
||||||
|
## `ArrayType`
|
||||||
|
|
||||||
|
`ArrayType` is instantiated as
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- The template must be usable with **two** type arguments (value type and allocator).
|
||||||
|
- Member types `value_type` and `iterator`.
|
||||||
|
- Constructors: default, copy, and move; and from an iterator range `(first, last)`.
|
||||||
|
- Member functions `begin()`, `end()`, `cbegin()`, `cend()`, `empty()`, `size()`, `max_size()`, `clear()`,
|
||||||
|
`operator[](size_type)`, `back()`, `push_back()`, `emplace_back()`, `pop_back()`, `resize()`,
|
||||||
|
`insert()` (single element, count, and range), `erase(pos)`, and `erase(first, last)`.
|
||||||
|
`basic_json::insert(pos, initializer_list)` goes through the range overload, so no initializer-list `insert` is
|
||||||
|
needed. `at(size_type)` is **not** required: [`basic_json::at(size_type)`](../../api/basic_json/at.md) checks the
|
||||||
|
index itself and then uses `operator[]`.
|
||||||
|
- `iterator` must be default-constructible, and it as well as the type returned by `cbegin()`/`cend()` must satisfy
|
||||||
|
[LegacyRandomAccessIterator](https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator).
|
||||||
|
A `#!cpp static_assert` only checks for
|
||||||
|
[LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator), but
|
||||||
|
[`dump`](../../api/basic_json/dump.md) (`cend() - 1`),
|
||||||
|
[`erase(idx)`](../../api/basic_json/erase.md) (`begin() + idx`), and the random-access operations of
|
||||||
|
[`basic_json::iterator`](../../api/basic_json/begin.md) require random access.
|
||||||
|
- The comparison operators, as for [`ObjectType`](#objecttype): `==` and `<`, or `==` and `<=>` under C++20.
|
||||||
|
|
||||||
|
### Required for individual functions
|
||||||
|
|
||||||
|
- A member type `value_type`, for [`to_bson`](../../api/basic_json/to_bson.md) of an array.
|
||||||
|
- A constructor from `(count, value)`, for
|
||||||
|
[`basic_json(size_type, const basic_json&)`](../../api/basic_json/basic_json.md).
|
||||||
|
- Swappability, via `#!cpp std::swap` or an ADL `swap`, for [`swap(array_t&)`](../../api/basic_json/swap.md).
|
||||||
|
|
||||||
|
!!! note "`capacity()` is optional"
|
||||||
|
|
||||||
|
With [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md) enabled, the library reads `array_t::capacity()`
|
||||||
|
to find out whether adding an element reallocated the array and moved its elements, which would invalidate the
|
||||||
|
parent pointers. An array type without a `capacity()` member function is handled conservatively: the parent
|
||||||
|
pointers of all elements are refreshed after every insertion, which makes adding *n* elements cost O(*n*²). Only
|
||||||
|
diagnostics builds pay this; without them `capacity()` is never called.
|
||||||
|
|
||||||
|
!!! tip "Reference implementation"
|
||||||
|
|
||||||
|
`docs/mkdocs/docs/examples/custom_array_type.hpp` wraps a private `#!cpp std::vector` and satisfies every
|
||||||
|
requirement above -- a good starting point for a custom `ArrayType`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/custom_array_type.hpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Compiling and using it"
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/custom_array_type.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/custom_array_type.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compatible containers
|
||||||
|
|
||||||
|
| Container | Notes |
|
||||||
|
|---------------------------------------------------------|-------------------------------------------------------------------------------------------|
|
||||||
|
| `#!cpp std::vector` (default) | |
|
||||||
|
| `#!cpp std::deque` | references survive appends, but not insertions elsewhere; see the `capacity()` note above |
|
||||||
|
| `#!cpp std::pmr::vector` | through an alias, as the allocator comes from `AllocatorType` instead |
|
||||||
|
| `boost::container::vector`, `deque`, `devector` | |
|
||||||
|
| `boost::container::stable_vector` | the only one tried that keeps references valid across *every* insertion |
|
||||||
|
| `boost::container::small_vector`, `folly::small_vector` | through an alias that fixes the inline capacity |
|
||||||
|
| `boost::container::static_vector` | through the same kind of alias, for arrays that stay within the fixed capacity |
|
||||||
|
| `folly::fbvector` | requires C++20, see the note above |
|
||||||
|
|
||||||
|
### Containers that cannot be used
|
||||||
|
|
||||||
|
| Container | Reason |
|
||||||
|
|-------------------------------------|-----------------------------------------------------------------------------------------------|
|
||||||
|
| `#!cpp std::list` | no `operator[]`, and no random-access iterators |
|
||||||
|
| `eastl::vector`, `QList`, `QVector` | no `max_size()`; they handle the incomplete value type fine |
|
||||||
|
| `absl::InlinedVector` | requires a complete value type, see the note above |
|
||||||
|
| `absl::FixedArray` | the size is fixed at construction, so `resize`, `push_back`, `insert` and `erase` are missing |
|
||||||
|
|
||||||
|
## `StringType`
|
||||||
|
|
||||||
|
`StringType` is used **both** for JSON string values and for the keys of JSON objects
|
||||||
|
(`string_t` and `object_t::key_type`).
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- A member type `value_type` that is one byte wide and `char`-compatible. The library stores and processes UTF-8
|
||||||
|
encoded `char` data and hands `data()` to `#!cpp std::strtoull`/`#!cpp std::strtoll`.
|
||||||
|
`#!cpp std::wstring`, `#!cpp std::u16string`, and `#!cpp std::u32string` are **not** valid choices; see the FAQ on
|
||||||
|
[wide string handling](../../home/faq.md#wide-string-handling).
|
||||||
|
- Constructors: default, copy, move, from `#!cpp const char*` (which must not be `#!cpp explicit`), from
|
||||||
|
`#!cpp (const char*, size_type)`, and from `#!cpp (size_type, char)`; and copy or move assignment.
|
||||||
|
- Member functions `size()`, `clear()`, `resize(n, c)`, `data()`, `push_back(char)`, and `operator[]`
|
||||||
|
(const and non-const, returning references). `c_str()` and `back()` are **not** required.
|
||||||
|
- `data()` must return a pointer to a contiguous, **null-terminated** buffer -- the parser hands it to
|
||||||
|
`#!cpp std::strtoull`. A type whose `data()` is not null-terminated does not fail to compile; it silently
|
||||||
|
misparses numbers.
|
||||||
|
- `append(const char*, size_type)`, used by [`dump`](../../api/basic_json/dump.md), and `append(const StringType&)`,
|
||||||
|
used by the CBOR reader for indefinite-length strings. The library's internal string concatenation additionally has
|
||||||
|
to append a `#!cpp char` and a `#!cpp const char*`; for each it selects between `append(arg)`, `#!cpp operator+=`,
|
||||||
|
`append(first, last)`, and `append(data, size)`.
|
||||||
|
- The comparison operator `==` against another `StringType`, and `<` for use as a key of the chosen
|
||||||
|
[`ObjectType`](#objecttype) (with the default comparator, `#!cpp std::less<>` must be able to compare two
|
||||||
|
`StringType` values, and a `StringType` with the key types used for lookup). `!=` is never applied to a
|
||||||
|
`StringType`, and `==` against `#!cpp const char*` is resolved by the implicit `#!cpp const char*` constructor.
|
||||||
|
|
||||||
|
### Required for the binary formats
|
||||||
|
|
||||||
|
- `resize(n)`, used by the readers to make room for a block of bytes.
|
||||||
|
- Non-const `operator[]`, into which the readers `#!cpp std::memcpy` those bytes. A non-`#!cpp const` `data()` would
|
||||||
|
serve just as well, but `#!cpp std::string` has only had one since C++17, and the library still supports C++11.
|
||||||
|
|
||||||
|
### Required for JSON Pointer, `flatten`, and `diff`
|
||||||
|
|
||||||
|
- A static member `npos` and the member function `find_first_of(char, size_type)` -- together with `data()`,
|
||||||
|
`reserve(n)`, and `append(const char*, size_type)` they implement the escaping and unescaping of reference tokens
|
||||||
|
described in RFC 6901. Neither `find(const StringType&, size_type)`, nor `substr(pos, count)`, nor
|
||||||
|
`replace(pos, count, const StringType&)` is required.
|
||||||
|
- `empty()`.
|
||||||
|
- `begin()` and `end()` -- used by
|
||||||
|
[`operator[](const json_pointer&)`](../../api/basic_json/operator%5B%5D.md) to decide whether a reference token
|
||||||
|
denotes an array index.
|
||||||
|
|
||||||
|
### Required for other functionality
|
||||||
|
|
||||||
|
| Functionality | Additional requirement |
|
||||||
|
|-----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| [`diff`](../../api/basic_json/diff.md), [`items`](../../api/basic_json/items.md), [`std::hash`](../../api/basic_json/std_hash.md) | conversion of a `#!cpp std::size_t` to `StringType`: either assignability from the result of `#!cpp std::to_string`, or an ADL overload `#!cpp void int_to_string(StringType&, std::size_t)` |
|
||||||
|
| [`std::hash<basic_json>`](../../api/basic_json/std_hash.md) | additionally a specialization of `#!cpp std::hash<StringType>` |
|
||||||
|
| [`to_bson`](../../api/basic_json/to_bson.md) | `find(value_type)` and `npos` |
|
||||||
|
| [`parse`](../../api/basic_json/parse.md) from a `string_t` | the input adapters must accept it; otherwise pass a character range |
|
||||||
|
| `#!cpp operator<<(std::ostream&, const json_pointer&)` | streamability to `#!cpp std::ostream` |
|
||||||
|
| exception messages | `data()` and `size()`, or `begin()` and `end()` |
|
||||||
|
|
||||||
|
### Compatible types
|
||||||
|
|
||||||
|
| Type | Notes |
|
||||||
|
|-----------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `#!cpp std::string` (default) | |
|
||||||
|
| `#!cpp std::basic_string` with a custom **stateless** allocator | |
|
||||||
|
| `#!cpp std::pmr::string` | see the warning below before relying on the memory resource |
|
||||||
|
| `boost::container::string` | needs a user-supplied `#!cpp std::hash` specialization (Boost provides `boost::hash` instead) |
|
||||||
|
| `folly::fbstring` | requires C++20, see the note above |
|
||||||
|
| `eastl::string` | needs a user-supplied `#!cpp std::hash` and an ADL `int_to_string` (it is not assignable from a `#!cpp std::string`); [`parse`](../../api/basic_json/parse.md) does not accept it directly -- pass a character range or a `#!cpp std::string` |
|
||||||
|
| a custom string class in a user-defined namespace | if the requirements above are met |
|
||||||
|
|
||||||
|
### Types that cannot be used
|
||||||
|
|
||||||
|
| Type | Reason |
|
||||||
|
|----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
|
||||||
|
| `#!cpp std::wstring`, `#!cpp std::u16string`, `#!cpp std::u32string` | the character type is not one byte wide |
|
||||||
|
| `#!cpp std::u8string` | one byte wide, but `#!cpp char8_t` is not `#!cpp char`-compatible |
|
||||||
|
| `absl::Cord` | no `value_type`, and the storage is not contiguous |
|
||||||
|
| `QString` | no `append(const char*, size_type)`; its `QChar` is also two bytes wide, though that is never diagnosed |
|
||||||
|
|
||||||
|
!!! warning "A `std::pmr::string` mostly does not use the memory resource you choose"
|
||||||
|
|
||||||
|
`basic_json` cannot be given an allocator or a memory resource. `AllocatorType` is default-constructed at every
|
||||||
|
allocation and has to be stateless (see [`AllocatorType`](#allocatortype)), and string values the library creates
|
||||||
|
are constructed with their own default allocator. So:
|
||||||
|
|
||||||
|
- Every string the library itself produces -- from [`parse`](../../api/basic_json/parse.md), from
|
||||||
|
[`dump`](../../api/basic_json/dump.md), or by default construction -- allocates from
|
||||||
|
`#!cpp std::pmr::get_default_resource()`.
|
||||||
|
- **Copying** an arena-backed string into a value silently drops its memory resource: the copy lands on the
|
||||||
|
default resource, because `#!cpp std::pmr::polymorphic_allocator` does not propagate on copy construction.
|
||||||
|
Nothing warns about this.
|
||||||
|
- **Moving** one in does keep it, and later growth still allocates from that arena -- but it does not survive a
|
||||||
|
copy of the enclosing `basic_json`.
|
||||||
|
- Passing `#!cpp std::pmr::polymorphic_allocator` as `AllocatorType` does not work around any of this; it does
|
||||||
|
not compile.
|
||||||
|
|
||||||
|
Apart from moving a string in, the only way to redirect these allocations is the process-global
|
||||||
|
`#!cpp std::pmr::set_default_resource()`.
|
||||||
|
|
||||||
|
!!! tip "Reference implementation"
|
||||||
|
|
||||||
|
`docs/mkdocs/docs/examples/custom_string_type.hpp` wraps a private `#!cpp std::string` and satisfies every
|
||||||
|
requirement above -- a good starting point for a custom `StringType`. The unit test
|
||||||
|
`tests/src/unit-alt-string.cpp` contains a more thorough variant, `alt_string`, exercised against a larger part
|
||||||
|
of the API.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/custom_string_type.hpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Compiling and using it"
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/custom_string_type.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/custom_string_type.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
## `BooleanType`
|
||||||
|
|
||||||
|
`boolean_t` is stored **directly** inside `basic_json`, as a member of an anonymous union.
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- A literal type that is trivially default-constructible, trivially copyable, and trivially destructible; otherwise the
|
||||||
|
union's special member functions are deleted.
|
||||||
|
- **Implicitly** convertible from `#!cpp bool` -- an `#!cpp explicit` constructor is not enough, because the
|
||||||
|
`to_json` overload for a custom `BooleanType` is constrained on `#!cpp std::is_convertible` -- and contextually
|
||||||
|
convertible to `#!cpp bool` (here an `#!cpp explicit operator bool` is fine).
|
||||||
|
- Comparison operators `==`, `!=`, `<`, `<=`, `>`, `>=` (or `<=>`).
|
||||||
|
- Convertible from and to `#!cpp bool` through the serializer, because
|
||||||
|
[`get<bool>()`](../../api/basic_json/get.md) is used internally.
|
||||||
|
|
||||||
|
There is little reason to use anything other than `#!cpp bool` here.
|
||||||
|
|
||||||
|
### Compatible types
|
||||||
|
|
||||||
|
`#!cpp bool` is the only usable choice. Another trivially copyable type that is implicitly convertible to and from
|
||||||
|
`#!cpp bool` -- `#!cpp std::uint8_t`, say -- does compile, and JSON booleans still round-trip, but the type then
|
||||||
|
serves as both `boolean_t` and an ordinary integer: `basic_json` can no longer be constructed or assigned from a
|
||||||
|
`#!cpp std::uint8_t` at all (the boolean and unsigned-integer `to_json` overloads become ambiguous), and
|
||||||
|
[`get<std::uint8_t>()`](../../api/basic_json/get.md) on a number throws
|
||||||
|
[`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) instead of returning the value.
|
||||||
|
|
||||||
|
## `NumberIntegerType` and `NumberUnsignedType`
|
||||||
|
|
||||||
|
Both types are stored **directly** inside `basic_json`'s union.
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- `#!cpp std::is_integral` must be satisfied: `NumberIntegerType` must be a **signed** integer type,
|
||||||
|
`NumberUnsignedType` an **unsigned** integer type. Class types are not supported -- among others, the constructors
|
||||||
|
taking integer values are constrained on `#!cpp std::is_integral`.
|
||||||
|
- Trivially default-constructible, trivially copyable, and trivially destructible (union member).
|
||||||
|
- `#!cpp std::numeric_limits` must be specialized for both types.
|
||||||
|
- `NumberUnsignedType` must be able to represent the absolute value of every `NumberIntegerType` value; serialization
|
||||||
|
of negative numbers converts the value to `NumberUnsignedType`. A `#!cpp static_assert` requires it to be at least as
|
||||||
|
wide as `NumberIntegerType`, which is what that amounts to for the standard integer types.
|
||||||
|
- Both types must fit into the internal 64-character number buffer used by
|
||||||
|
[`dump`](../../api/basic_json/dump.md), which is the case for all standard integer types.
|
||||||
|
- [`std::hash<basic_json>`](../../api/basic_json/std_hash.md) additionally requires `#!cpp std::hash` specializations.
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
The number types influence what the parser accepts: an integer literal that does not round-trip through the chosen type
|
||||||
|
is stored as [`number_float_t`](../../api/basic_json/number_float_t.md) instead. Choosing types narrower than 64 bits
|
||||||
|
therefore silently changes parse results rather than raising an error. See
|
||||||
|
[Number Handling](number_handling.md) for details.
|
||||||
|
|
||||||
|
### Compatible types
|
||||||
|
|
||||||
|
| Type pair | Support |
|
||||||
|
|----------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `#!cpp std::int64_t` / `#!cpp std::uint64_t` (default) | full |
|
||||||
|
| `#!cpp std::int32_t` / `#!cpp std::uint32_t`, `#!cpp long long` / `#!cpp unsigned long long` | full; narrower types change which literals the parser can represent |
|
||||||
|
| any other pair of standard signed/unsigned integer types | full |
|
||||||
|
| class types, enumerations | not usable; `#!cpp std::is_integral` must hold |
|
||||||
|
| `#!cpp bool`, or a type already used for another member of the union | not usable; `#!cpp std::is_integral<bool>` is in fact `#!cpp true`, but the `get_impl_ptr` overloads for `boolean_t`, `number_integer_t`, `number_unsigned_t` and `number_float_t` would collide |
|
||||||
|
|
||||||
|
## `NumberFloatType`
|
||||||
|
|
||||||
|
`number_float_t` is stored **directly** inside `basic_json`'s union.
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- Trivially default-constructible, trivially copyable, and trivially destructible (union member).
|
||||||
|
- `#!cpp std::numeric_limits` must be specialized; `max_digits10` is used to size the conversion.
|
||||||
|
- `#!cpp std::isfinite` must be applicable to the type.
|
||||||
|
|
||||||
|
### Required for parsing and serialization
|
||||||
|
|
||||||
|
`NumberFloatType` must be one of `#!cpp float`, `#!cpp double`, or `#!cpp long double`:
|
||||||
|
|
||||||
|
- The [parser](../parsing/index.md) converts number literals with `#!cpp std::strtof`, `#!cpp std::strtod`, or
|
||||||
|
`#!cpp std::strtold`; the library provides overloads for exactly these three types.
|
||||||
|
- [`dump`](../../api/basic_json/dump.md) falls back to `#!cpp std::snprintf` with the `%g` and `%Lg` conversion
|
||||||
|
specifiers, for which the library likewise provides only `#!cpp double` and `#!cpp long double` overloads
|
||||||
|
(`#!cpp float` is promoted to `#!cpp double`).
|
||||||
|
|
||||||
|
If `#!cpp std::numeric_limits<NumberFloatType>` describes an IEEE 754 binary32 or binary64 number, `dump` uses the
|
||||||
|
Grisu2 algorithm, which produces the shortest representation that round-trips. Otherwise the `snprintf` fallback with
|
||||||
|
`max_digits10` digits is used.
|
||||||
|
|
||||||
|
### Required for the binary formats
|
||||||
|
|
||||||
|
`NumberFloatType` must be `#!cpp float` or `#!cpp double`. The writers for
|
||||||
|
[CBOR, MessagePack, UBJSON, BJData, and BSON](../binary_formats/index.md) map a floating-point value onto an IEEE 754
|
||||||
|
binary32 or binary64 field and have no encoding for `#!cpp long double`.
|
||||||
|
|
||||||
|
### Compatible types
|
||||||
|
|
||||||
|
| Type | Support |
|
||||||
|
|--------------------------|-----------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `#!cpp double` (default) | full; short round-trip output through Grisu2 |
|
||||||
|
| `#!cpp float` | full; short round-trip output through Grisu2 |
|
||||||
|
| `#!cpp long double` | `dump` and `parse` only; the binary format writers do not compile, as they only handle IEEE 754 binary32 and binary64 |
|
||||||
|
| any other type | not usable |
|
||||||
|
|
||||||
|
## `AllocatorType`
|
||||||
|
|
||||||
|
`AllocatorType` is instantiated with **one** argument, for each of `object_t`, `array_t`, `string_t`, `binary_t`,
|
||||||
|
`basic_json`, and `#!cpp std::pair<const StringType, basic_json>`.
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- The template must be usable with exactly one type argument. The library instantiates `AllocatorType<T>` directly and
|
||||||
|
never uses `#!cpp std::allocator_traits<...>::rebind_alloc`.
|
||||||
|
- It must satisfy the [Allocator](https://en.cppreference.com/w/cpp/named_req/Allocator) named requirement so that
|
||||||
|
`#!cpp std::allocator_traits` can be used with it.
|
||||||
|
- It must be **default-constructible and stateless**. Objects are allocated with a default-constructed allocator and
|
||||||
|
deallocated with a *different* default-constructed allocator, and
|
||||||
|
[`get_allocator()`](../../api/basic_json/get_allocator.md) returns a default-constructed instance. Allocators
|
||||||
|
carrying state are not supported, so there is no way to tell a `basic_json` where to allocate from; see the note
|
||||||
|
under [`StringType`](#stringtype) for what that means in practice. A stateful allocator is **not diagnosed**: it
|
||||||
|
compiles and silently ignores the state.
|
||||||
|
- It must support **incomplete types**: `AllocatorType<basic_json>` is instantiated inside the definition of
|
||||||
|
`basic_json` itself.
|
||||||
|
- `#!cpp std::allocator_traits<AllocatorType<basic_json>>::pointer` becomes
|
||||||
|
[`basic_json::pointer`](../../api/basic_json/index.md#container-types), and iterators are constructed from raw
|
||||||
|
`#!cpp basic_json*` values. The `pointer` type must therefore be a plain pointer; fancy pointers are not supported.
|
||||||
|
|
||||||
|
### Compatible types
|
||||||
|
|
||||||
|
| Type | Support |
|
||||||
|
|-------------------------------------------------------------------|----------------------------------------|
|
||||||
|
| `#!cpp std::allocator` (default) | full |
|
||||||
|
| a custom stateless allocator template | full |
|
||||||
|
| stateful allocators, e.g. `#!cpp std::pmr::polymorphic_allocator` | not usable; see the requirements above |
|
||||||
|
|
||||||
|
## `JSONSerializer`
|
||||||
|
|
||||||
|
`JSONSerializer` is instantiated as `JSONSerializer<T, void>` and defaults to
|
||||||
|
[`adl_serializer`](../../api/adl_serializer/index.md).
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- The template must accept **two** type arguments. It does not have to give the second one a default -- `basic_json`
|
||||||
|
declares the parameter as `#!cpp template<typename T, typename SFINAE = void> class JSONSerializer`, so uses such as
|
||||||
|
`#!cpp JSONSerializer<T>` inside the library supply `#!cpp void` themselves. The second parameter exists so that
|
||||||
|
partial specializations can be constrained by SFINAE.
|
||||||
|
- For every type `T` that is converted **to** a JSON value, a static member function
|
||||||
|
`#!cpp static void to_json(basic_json&, T)` must exist.
|
||||||
|
- For every type `T` that is converted **from** a JSON value, either
|
||||||
|
`#!cpp static void from_json(const basic_json&, T&)` or `#!cpp static T from_json(const basic_json&)` must exist.
|
||||||
|
The latter form is required for types that are not default-constructible; see
|
||||||
|
[Arbitrary Types Conversions](../arbitrary_types.md).
|
||||||
|
- To support the [converting constructor](../../api/basic_json/basic_json.md) between different `basic_json`
|
||||||
|
specializations, `to_json` must be available for `boolean_t`, `number_integer_t`, `number_unsigned_t`,
|
||||||
|
`number_float_t`, `string_t`, `object_t`, `array_t`, and `binary_t` of the *source* specialization.
|
||||||
|
|
||||||
|
### Compatible types
|
||||||
|
|
||||||
|
| Type | Support |
|
||||||
|
|---------------------------------------------------------------------------|-------------------------------------------------------------------|
|
||||||
|
| [`nlohmann::adl_serializer`](../../api/adl_serializer/index.md) (default) | full |
|
||||||
|
| a class template deriving from `adl_serializer` | full; the usual way to change behavior while keeping the defaults |
|
||||||
|
| an unrelated template with the same interface | full, but it has to handle every type the library converts |
|
||||||
|
|
||||||
|
## `BinaryType`
|
||||||
|
|
||||||
|
`BinaryType` is not a JSON type; it is used for the byte strings of the
|
||||||
|
[binary formats](../binary_formats/index.md). It is wrapped as
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- A non-`final` class type -- [`byte_container_with_subtype`](../../api/byte_container_with_subtype/index.md) derives
|
||||||
|
from it publicly.
|
||||||
|
- A member type `value_type` that is **exactly one byte** wide (e.g., `#!cpp std::uint8_t`, `#!cpp char`, or
|
||||||
|
`#!cpp std::byte`). Readers and writers reinterpret the container's storage as raw bytes, so a wider `value_type` is
|
||||||
|
rejected with a `#!cpp static_assert`.
|
||||||
|
- Contiguous storage: the binary readers `#!cpp std::memcpy` into `#!cpp &binary[n]`, the writers `reinterpret_cast`
|
||||||
|
`data()`. `#!cpp data() + n` would do for the readers too, but they share one helper with
|
||||||
|
[`StringType`](#stringtype), whose non-`#!cpp const` `data()` is C++17 and later only.
|
||||||
|
- Default-constructible, copy-constructible, and move-constructible.
|
||||||
|
- Member functions `size()`, `empty()`, `data()`, `resize()`, `operator[]`, `back()`, `begin()`, `end()`, `cbegin()`,
|
||||||
|
and `cend()` with random-access iterators, and `insert(pos, first, last)`, which the CBOR reader uses to join the
|
||||||
|
chunks of an indefinite-length byte string. `push_back()` is **not** required.
|
||||||
|
- Comparison operators: `==` is used by
|
||||||
|
[`byte_container_with_subtype`](../../api/byte_container_with_subtype/index.md), the relational operators by
|
||||||
|
[`basic_json`'s comparison operators](../../api/basic_json/operator_le.md).
|
||||||
|
|
||||||
|
### Required for individual functions
|
||||||
|
|
||||||
|
- `clear()`, for [`basic_json::clear()`](../../api/basic_json/clear.md).
|
||||||
|
|
||||||
|
`max_size()`, `at()`, `reserve()`, `erase()`, `pop_back()`, and `emplace_back()` are **not** used at all.
|
||||||
|
|
||||||
|
See [`binary_t`](../../api/basic_json/binary_t.md) for how a non-default `BinaryType` changes the meaning of assigning
|
||||||
|
such a container to a `basic_json` value.
|
||||||
|
|
||||||
|
!!! tip "Reference implementation"
|
||||||
|
|
||||||
|
`docs/mkdocs/docs/examples/custom_binary_type.hpp` wraps a private `#!cpp std::vector<std::uint8_t>` and satisfies
|
||||||
|
every requirement above -- a good starting point for a custom `BinaryType`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/custom_binary_type.hpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Compiling and using it"
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/custom_binary_type.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/custom_binary_type.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compatible containers
|
||||||
|
|
||||||
|
| Container | Notes |
|
||||||
|
|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------------|
|
||||||
|
| `#!cpp std::vector<std::uint8_t>` (default) | |
|
||||||
|
| `#!cpp std::vector<char>`, `#!cpp std::vector<std::byte>` | `dump()` writes the bytes as 0..255 whichever is used |
|
||||||
|
| `boost::container::vector<std::uint8_t>`, `boost::container::small_vector<std::uint8_t, N>` | |
|
||||||
|
| `absl::InlinedVector<std::uint8_t, N>` | usable here, unlike as an `ArrayType`, because the value type is complete |
|
||||||
|
| `eastl::vector<std::uint8_t>` | usable here, unlike as an `ArrayType`, because `max_size()` is not needed |
|
||||||
|
| `folly::fbvector<std::uint8_t>` | requires C++20, see the note above |
|
||||||
|
|
||||||
|
### Containers that cannot be used
|
||||||
|
|
||||||
|
| Container | Reason |
|
||||||
|
|------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `QByteArray` | no `empty()` (it spells that `isEmpty()`); its `insert` takes an index rather than an iterator; and it converts to `string_t`, which makes `to_json` ambiguous between a string and a binary value |
|
||||||
|
| `#!cpp std::string` | `binary_t::container_type` and `string_t` would be the same type, so the two [`swap`](../../api/basic_json/swap.md) overloads collide and `basic_json` cannot be instantiated at all |
|
||||||
|
| `#!cpp std::deque<std::uint8_t>` | storage is not contiguous, so there is no `data()` |
|
||||||
|
| containers whose `value_type` is wider than one byte | see above -- accepted by the compiler, wrong at runtime |
|
||||||
|
|
||||||
|
## `CustomBaseClass`
|
||||||
|
|
||||||
|
`CustomBaseClass` is an extension point: unless it is `#!cpp void` (the default, which selects the empty
|
||||||
|
`nlohmann::json_default_base`), `basic_json` publicly derives from it.
|
||||||
|
|
||||||
|
### Always required
|
||||||
|
|
||||||
|
- A non-`final`, default-constructible class type.
|
||||||
|
- `basic_json` is copy-/move-constructible and copy-/move-assignable only if `CustomBaseClass` is.
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
`basic_json` is documented to be a
|
||||||
|
[StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType). Because `basic_json` has
|
||||||
|
non-static data members of its own, a `CustomBaseClass` with non-static data members forfeits this guarantee.
|
||||||
|
|
||||||
|
Note the namespace of `CustomBaseClass` becomes an associated namespace of `basic_json` for the purpose of
|
||||||
|
argument-dependent lookup.
|
||||||
|
|
||||||
|
See [`json_base_class_t`](../../api/basic_json/json_base_class_t.md) for an example.
|
||||||
|
|
||||||
|
### Compatible types
|
||||||
|
|
||||||
|
| Type | Support |
|
||||||
|
|----------------------------------------------|----------------------------------------------------------------------------|
|
||||||
|
| `#!cpp void` (default) | an empty base class is used; no effect on `basic_json` |
|
||||||
|
| any default-constructible, non-`final` class | full; see [`json_base_class_t`](../../api/basic_json/json_base_class_t.md) |
|
||||||
|
|
||||||
|
## Cross-specialization conversions
|
||||||
|
|
||||||
|
Converting a value from one `basic_json` specialization into another (see the
|
||||||
|
[converting constructor](../../api/basic_json/basic_json.md)) imposes two additional requirements that are not
|
||||||
|
diagnosed at compile time. With assertions enabled they abort on the `#!cpp JSON_ASSERT` at the end of the converting
|
||||||
|
constructor; under `#!cpp NDEBUG` they fail **silently** at runtime:
|
||||||
|
|
||||||
|
- The target `string_t` must be directly constructible from the source `string_t`. Otherwise the string is converted to
|
||||||
|
an array of character codes.
|
||||||
|
- The target `object_t::key_type` must be directly constructible from the source object's key type. Otherwise the
|
||||||
|
object is converted to an array of key/value pairs.
|
||||||
|
|
||||||
|
See [issue #3425](https://github.com/nlohmann/json/issues/3425), [`string_t`](../../api/basic_json/string_t.md), and
|
||||||
|
[`object_t`](../../api/basic_json/object_t.md).
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
- [Types](index.md) -- overview of how JSON values are stored
|
||||||
|
- [Number Handling](number_handling.md) -- how the number types affect parsing and serialization
|
||||||
|
- [Object Order](../object_order.md) -- using an insertion-ordered `ObjectType`
|
||||||
|
- [`basic_json`](../../api/basic_json/index.md) -- API documentation of the class template
|
||||||
@@ -8,72 +8,41 @@ the result of an internet search. If you know further customers of the library,
|
|||||||
## Space Exploration
|
## Space Exploration
|
||||||
|
|
||||||
- [**Peregrine Lunar Lander Flight 01**](https://en.wikipedia.org/wiki/Peregrine_Mission_One) - The library was used for payload management in the **Peregrine Moon Lander**, developed by **Astrobotic Technology** and launched as part of NASA's **Commercial Lunar Payload Services (CLPS)** program. After six days in orbit, the spacecraft was intentionally redirected into Earth's atmosphere, where it burned up over the Pacific Ocean on **January 18, 2024**.
|
- [**Peregrine Lunar Lander Flight 01**](https://en.wikipedia.org/wiki/Peregrine_Mission_One) - The library was used for payload management in the **Peregrine Moon Lander**, developed by **Astrobotic Technology** and launched as part of NASA's **Commercial Lunar Payload Services (CLPS)** program. After six days in orbit, the spacecraft was intentionally redirected into Earth's atmosphere, where it burned up over the Pacific Ocean on **January 18, 2024**.
|
||||||
- [**NASA Unsteady Pressure-Sensitive Paint Processing**](https://github.com/nasa/upsp-processing), NASA software for processing high-speed video recordings of wind tunnel tests on launch vehicle and aircraft models
|
|
||||||
- [**Terma TEMU**](https://temu.terma.com/docs/public/temu-release-notes/latest/copying/json-for-modern-cpp.html), an emulator of spacecraft on-board computers used to develop and validate flight software for European space missions
|
|
||||||
|
|
||||||
## Automotive
|
## Automotive
|
||||||
|
|
||||||
- [**Alexa Auto SDK**](https://github.com/alexa/alexa-auto-sdk), a software development kit enabling the integration of Alexa into automotive systems
|
- [**Alexa Auto SDK**](https://github.com/alexa/alexa-auto-sdk), a software development kit enabling the integration of Alexa into automotive systems
|
||||||
- [**Apollo**](https://github.com/ApolloAuto/apollo), a framework for building autonomous driving systems
|
- [**Apollo**](https://github.com/ApolloAuto/apollo), a framework for building autonomous driving systems
|
||||||
- [**Automotive Grade Linux (AGL)**](https://download.automotivelinux.org/AGL/release/jellyfish/latest/qemux86-64/deploy/licenses/nlohmann-json/), a collaborative open-source platform for automotive software development
|
- [**Automotive Grade Linux (AGL)**](https://download.automotivelinux.org/AGL/release/jellyfish/latest/qemux86-64/deploy/licenses/nlohmann-json/), a collaborative open-source platform for automotive software development
|
||||||
- [**Autoware**](https://github.com/autowarefoundation/autoware_universe), an open-source software stack for autonomous driving built on ROS 2
|
|
||||||
- [**Eclipse S-CORE**](https://github.com/eclipse-score/nlohmann_json), an open-source software platform for the software-defined vehicle backed by major automotive manufacturers and suppliers
|
|
||||||
- [**Genesis Motor** (infotainment)](http://webmanual.genesis.com/ccIC/AVNT/JW/KOR/English/reference010.html), a luxury automotive brand
|
- [**Genesis Motor** (infotainment)](http://webmanual.genesis.com/ccIC/AVNT/JW/KOR/English/reference010.html), a luxury automotive brand
|
||||||
- [**Hyundai** (infotainment)](https://www.hyundai.com/wsvc/ww/download.file.do?id=/content/hyundai/ww/data/opensource/data/GN7-2022/licenseCode/info), a global automotive brand
|
- [**Hyundai** (infotainment)](https://www.hyundai.com/wsvc/ww/download.file.do?id=/content/hyundai/ww/data/opensource/data/GN7-2022/licenseCode/info), a global automotive brand
|
||||||
- [**Kia** (infotainment)](http://webmanual.kia.com/PREM_GEN6/AVNT/RJPE/KOR/Korean/reference010.html), a global automotive brand
|
- [**Kia** (infotainment)](http://webmanual.kia.com/PREM_GEN6/AVNT/RJPE/KOR/Korean/reference010.html), a global automotive brand
|
||||||
- [**Mercedes-Benz Operating System (MB.OS)**](https://group.mercedes-benz.com/careers/about-us/mercedes-benz-operating-system/), a core component of the vehicle software ecosystem from Mercedes-Benz
|
- [**Mercedes-Benz Operating System (MB.OS)**](https://group.mercedes-benz.com/careers/about-us/mercedes-benz-operating-system/), a core component of the vehicle software ecosystem from Mercedes-Benz
|
||||||
- [**NVIDIA DRIVE OS**](https://developer.nvidia.com/docs/drive/drive-os/6.0.5/public/driveworks-nvcgf/dwx_open_source_attribution.html), the operating system and DriveWorks SDK powering NVIDIA's platform for autonomous vehicles
|
|
||||||
- [**Rivian** (infotainment)](https://assets.ctfassets.net/2md5qhoeajym/3cwyo4eoufk4yingUwusFt/ded2c47da620fdfc99c88c7156d2c1d8/In-Vehicle_OSS_Attribution_2024__11-24_.pdf), an electric vehicle manufacturer
|
- [**Rivian** (infotainment)](https://assets.ctfassets.net/2md5qhoeajym/3cwyo4eoufk4yingUwusFt/ded2c47da620fdfc99c88c7156d2c1d8/In-Vehicle_OSS_Attribution_2024__11-24_.pdf), an electric vehicle manufacturer
|
||||||
- [**Suzuki** (infotainment)](https://www.globalsuzuki.com/motorcycle/ipc/oss/oss_48KA_00.pdf), a global automotive and motorcycle manufacturer
|
- [**Suzuki** (infotainment)](https://www.globalsuzuki.com/motorcycle/ipc/oss/oss_48KA_00.pdf), a global automotive and motorcycle manufacturer
|
||||||
|
|
||||||
## Gaming and Entertainment
|
## Gaming and Entertainment
|
||||||
|
|
||||||
- [**Anno 117: Pax Romana**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a city-building strategy game set in the Roman Empire
|
|
||||||
- [**Assassin's Creed: Mirage**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a stealth-action game set in the Middle East, focusing on the journey of a young assassin with classic parkour and stealth mechanics
|
- [**Assassin's Creed: Mirage**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a stealth-action game set in the Middle East, focusing on the journey of a young assassin with classic parkour and stealth mechanics
|
||||||
- [**Battlefield 6**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a military first-person shooter known for its large-scale multiplayer battles
|
|
||||||
- [**Battlefield: REDSEC**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a free-to-play battle royale experience set in the Battlefield universe
|
|
||||||
- [**BioMenace: Remastered**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a remaster of the classic side-scrolling platform shooter
|
|
||||||
- [**Chasm: The Rift**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a first-person shooter blending horror and adventure, where players navigate dark realms and battle monsters
|
- [**Chasm: The Rift**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a first-person shooter blending horror and adventure, where players navigate dark realms and battle monsters
|
||||||
- [**College Football 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a college football simulation game featuring gameplay that mimics real-life college teams and competitions
|
- [**College Football 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a college football simulation game featuring gameplay that mimics real-life college teams and competitions
|
||||||
- [**College Football 26**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a college football simulation game featuring licensed teams and stadiums
|
|
||||||
- [**College Football 27**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), the latest installment of the college football simulation series
|
|
||||||
- [**Concepts**](https://concepts.app/en/licenses), a digital sketching app designed for creative professionals, offering flexible drawing tools for illustration, design, and brainstorming
|
- [**Concepts**](https://concepts.app/en/licenses), a digital sketching app designed for creative professionals, offering flexible drawing tools for illustration, design, and brainstorming
|
||||||
- [**Depthkit**](https://www.depthkit.tv/third-party-licenses), a tool for creating and capturing volumetric video, enabling immersive 3D experiences and interactive content
|
- [**Depthkit**](https://www.depthkit.tv/third-party-licenses), a tool for creating and capturing volumetric video, enabling immersive 3D experiences and interactive content
|
||||||
- [**Dune: Awakening**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an open-world survival MMO set on the desert planet Arrakis
|
|
||||||
- [**EA Sports FC 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an association football simulation with club, career, and online modes
|
|
||||||
- [**EA Sports FC 26**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), the latest installment of the association football simulation series
|
|
||||||
- [**EA Sports UFC 6**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a mixed martial arts fighting simulation
|
|
||||||
- [**FiveM**](https://github.com/citizenfx/fivem), a modification framework for Grand Theft Auto V that powers custom multiplayer servers
|
|
||||||
- [**FLUX:: Immersive**](https://doc.flux.audio/syrah/Credits.html), a suite of professional audio processing and immersive mixing plugins used in music and post-production
|
|
||||||
- [**IMG.LY**](https://img.ly/acknowledgements), a platform offering creative tools and SDKs for integrating advanced image and video editing in applications
|
- [**IMG.LY**](https://img.ly/acknowledgements), a platform offering creative tools and SDKs for integrating advanced image and video editing in applications
|
||||||
- [**immersivetech**](https://immersitech.io/open-source-third-party-software/), a technology company focused on immersive experiences, providing tools and solutions for virtual and augmented reality applications
|
|
||||||
- [**Kodi**](https://github.com/xbmc/xbmc/blob/master/xbmc/utils/JSONVariantWriter.cpp), a home theater and media center application
|
|
||||||
- [**LOOT**](https://loot.readthedocs.io/_/downloads/en/0.13.0/pdf/), a tool for optimizing the load order of game plugins, commonly used in The Elder Scrolls and Fallout series
|
- [**LOOT**](https://loot.readthedocs.io/_/downloads/en/0.13.0/pdf/), a tool for optimizing the load order of game plugins, commonly used in The Elder Scrolls and Fallout series
|
||||||
- [**LunaTranslator**](https://github.com/HIllya51/LunaTranslator/blob/main/src/NativeImpl/LunaSubprocess/aspatch.cpp), a real-time translation tool for visual novels
|
|
||||||
- [**MaaAssistantArknights**](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/dev-v2/src/MaaCore/Vision/Roguelike/BlackFlow/BlackFlowMapAnalyzer.cpp), an automation assistant for the mobile game Arknights
|
|
||||||
- [**Madden NFL 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a sports simulation game capturing the excitement of American football with realistic gameplay and team management features
|
- [**Madden NFL 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a sports simulation game capturing the excitement of American football with realistic gameplay and team management features
|
||||||
- [**Madden NFL 26**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an American football simulation with franchise and team management modes
|
|
||||||
- [**Madden NFL 27**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), the latest installment of the American football simulation series
|
|
||||||
- [**Marne**](https://marne.io/licenses), an unofficial private server platform for hosting custom Battlefield 1 game experiences
|
- [**Marne**](https://marne.io/licenses), an unofficial private server platform for hosting custom Battlefield 1 game experiences
|
||||||
- [**Minecraft**](https://www.minecraft.net/zh-hant/attribution), a popular sandbox video game
|
- [**Minecraft**](https://www.minecraft.net/zh-hant/attribution), a popular sandbox video game
|
||||||
- [**Mumble**](https://github.com/mumble-voip/mumble), a low-latency, open-source voice chat application widely used by gaming communities
|
|
||||||
- [**NHL 22**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a hockey simulation game offering realistic gameplay, team management, and various modes to enhance the hockey experience
|
- [**NHL 22**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a hockey simulation game offering realistic gameplay, team management, and various modes to enhance the hockey experience
|
||||||
- [**OBS Studio**](https://github.com/obsproject/obs-studio), a free and open-source suite for video recording and live streaming
|
|
||||||
- [**OpenRCT2**](https://github.com/OpenRCT2/OpenRCT2/blob/develop/src/openrct2/core/JsonFwd.hpp), an open source re-implementation of RollerCoaster Tycoon 2
|
|
||||||
- [**Pixelpart**](https://pixelpart.net/documentation/book/third-party.html), a 2D animation and video compositing software that allows users to create animated graphics and visual effects with a focus on simplicity and ease of use
|
- [**Pixelpart**](https://pixelpart.net/documentation/book/third-party.html), a 2D animation and video compositing software that allows users to create animated graphics and visual effects with a focus on simplicity and ease of use
|
||||||
- [**Razer Cortex**](https://mysupport.razer.com/app/answers/detail/a_id/14146/~/open-source-software-for-razer-software), a gaming performance optimizer and system booster designed to enhance the gaming experience
|
- [**Razer Cortex**](https://mysupport.razer.com/app/answers/detail/a_id/14146/~/open-source-software-for-razer-software), a gaming performance optimizer and system booster designed to enhance the gaming experience
|
||||||
- [**Red Dead Redemption II**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an open-world action-adventure game following an outlaw's story in the late 1800s, emphasizing deep storytelling and immersive gameplay
|
- [**Red Dead Redemption II**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an open-world action-adventure game following an outlaw's story in the late 1800s, emphasizing deep storytelling and immersive gameplay
|
||||||
- [**RetroArch**](https://github.com/libretro/RetroArch), a frontend for emulators, game engines, and media players built on the libretro API
|
|
||||||
- [**shadPS4**](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/user_manager.h), a PlayStation 4 emulator for Windows, Linux and macOS
|
|
||||||
- [**skate.**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a free-to-play skateboarding game set in an open world
|
|
||||||
- [**Snapchat**](https://www.snap.com/terms/license-android), a multimedia messaging and augmented reality app for communication and entertainment
|
- [**Snapchat**](https://www.snap.com/terms/license-android), a multimedia messaging and augmented reality app for communication and entertainment
|
||||||
- [**Steel Century Groove**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an action game released in 2026
|
|
||||||
- [**Sunshine**](https://github.com/LizardByte/Sunshine/blob/master/src/confighttp.h), a self-hosted game streaming host compatible with Moonlight clients
|
|
||||||
- [**Tactics Ogre: Reborn**](https://www.square-enix-games.com/en_US/documents/tactics-ogre-reborn-pc-installer-software-and-associated-plug-ins-disclosure), a tactical role-playing game featuring strategic battles and deep storytelling elements
|
- [**Tactics Ogre: Reborn**](https://www.square-enix-games.com/en_US/documents/tactics-ogre-reborn-pc-installer-software-and-associated-plug-ins-disclosure), a tactical role-playing game featuring strategic battles and deep storytelling elements
|
||||||
- [**Throne and Liberty**](https://www.amazon.com/gp/help/customer/display.html?nodeId=T7fLNw5oAevCMtJFPj&pop-up=1), an MMORPG that offers an expansive fantasy world with dynamic gameplay and immersive storytelling
|
- [**Throne and Liberty**](https://www.amazon.com/gp/help/customer/display.html?nodeId=T7fLNw5oAevCMtJFPj&pop-up=1), an MMORPG that offers an expansive fantasy world with dynamic gameplay and immersive storytelling
|
||||||
- [**Unity Vivox**](https://docs.unity3d.com/Packages/com.unity.services.vivox@15.1/license/Third%20Party%20Notices.html), a communication service that enables voice and text chat functionality in multiplayer games developed with Unity
|
- [**Unity Vivox**](https://docs.unity3d.com/Packages/com.unity.services.vivox@15.1/license/Third%20Party%20Notices.html), a communication service that enables voice and text chat functionality in multiplayer games developed with Unity
|
||||||
- [**xemu**](https://github.com/xemu-project/xemu), an emulator of the original Xbox console
|
|
||||||
- [**Zool: Redimensioned**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a modern reimagining of the classic platformer featuring fast-paced gameplay and vibrant environments
|
- [**Zool: Redimensioned**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a modern reimagining of the classic platformer featuring fast-paced gameplay and vibrant environments
|
||||||
|
- [**immersivetech**](https://immersitech.io/open-source-third-party-software/), a technology company focused on immersive experiences, providing tools and solutions for virtual and augmented reality applications
|
||||||
|
|
||||||
## Consumer Electronics
|
## Consumer Electronics
|
||||||
|
|
||||||
@@ -81,195 +50,109 @@ the result of an internet search. If you know further customers of the library,
|
|||||||
- [**Canon CanoScan LIDE**](https://carolburo.com/wp-content/uploads/2024/06/LiDE400_OnlineManual_Win_FR_V02.pdf), a series of flatbed scanners offering high-resolution image scanning for home and office use
|
- [**Canon CanoScan LIDE**](https://carolburo.com/wp-content/uploads/2024/06/LiDE400_OnlineManual_Win_FR_V02.pdf), a series of flatbed scanners offering high-resolution image scanning for home and office use
|
||||||
- [**Canon PIXMA Printers**](https://www.mediaexpert.pl/products/files/73/7338196/Instrukcja-obslugi-CANON-Pixma-TS7450i.pdf), a line of all-in-one inkjet printers known for high-quality printing and wireless connectivity
|
- [**Canon PIXMA Printers**](https://www.mediaexpert.pl/products/files/73/7338196/Instrukcja-obslugi-CANON-Pixma-TS7450i.pdf), a line of all-in-one inkjet printers known for high-quality printing and wireless connectivity
|
||||||
- [**Cisco Webex Desk Camera**](https://www.cisco.com/c/dam/en_us/about/doing_business/open_source/docs/CiscoWebexDeskCamera-23-1622100417.pdf), a video camera designed for professional-quality video conferencing and remote collaboration
|
- [**Cisco Webex Desk Camera**](https://www.cisco.com/c/dam/en_us/about/doing_business/open_source/docs/CiscoWebexDeskCamera-23-1622100417.pdf), a video camera designed for professional-quality video conferencing and remote collaboration
|
||||||
- [**DJI Edge SDK**](https://github.com/dji-sdk/Edge-SDK-V2-Demo), the reference applications for DJI's Edge SDK, used to build edge computing services on DJI drone docks
|
|
||||||
- [**Elgato Stream Deck**](https://github.com/elgatosf/streamdeck-obs-plugin2), a family of programmable control surfaces for content creators and their plugin ecosystem
|
|
||||||
- [**Instagrid**](https://instagrid.co/intellectual-property/foss), a manufacturer of portable, high-performance battery systems for professional mobile power supply
|
|
||||||
- [**iRobot**](https://iot-content.irobot.com/iw/sfsites/c/cms/delivery/media/MCKRLTPDJSSJBNJKDA5SG5UVVIIQ), a manufacturer of autonomous home robots including the Roomba vacuum cleaner range
|
|
||||||
- [**Logitech Logi Bolt**](https://opensource.logitech.com/wiki/Logi_BoltApp/), the management application for Logitech's secure wireless connectivity technology
|
|
||||||
- [**Novitus**](https://novitus.pl/licencjepensource), a manufacturer of fiscal cash registers and point-of-sale devices
|
|
||||||
- [**Philips Hue Personal Wireless Lighting**](http://2ak5ape.257.cz/), a smart lighting system for customizable and wireless home illumination
|
- [**Philips Hue Personal Wireless Lighting**](http://2ak5ape.257.cz/), a smart lighting system for customizable and wireless home illumination
|
||||||
- [**Ray-Ban Meta Smart glasses**](https://www.meta.com/de/en/legal/smart-glasses/third-party-notices-android/03/), a pair of smart glasses designed for capturing photos and videos with integrated connectivity and social features
|
- [**Ray-Ban Meta Smart glasses**](https://www.meta.com/de/en/legal/smart-glasses/third-party-notices-android/03/), a pair of smart glasses designed for capturing photos and videos with integrated connectivity and social features
|
||||||
- [**Razer Synapse**](https://mysupport.razer.com/app/answers/detail/a_id/14146/~/open-source-software-for-razer-software), a unified configuration software enabling hardware customization for Razer devices
|
- [**Razer Synapse**](https://mysupport.razer.com/app/answers/detail/a_id/14146/~/open-source-software-for-razer-software), a unified configuration software enabling hardware customization for Razer devices
|
||||||
- [**Sharp Professional Displays**](https://jp.sharp/restricted/business/lcd-display/cms/images/source_pnla862/PN-LA652_752_862_LicenseInformation.pdf), a range of large-format interactive displays for business and education
|
|
||||||
- [**Siemens SINEMA Remote Connect**](https://cache.industry.siemens.com/dl/files/790/109793790/att_1054961/v2/OSS_SINEMA-RC_86.pdf), a remote connectivity solution for monitoring and managing industrial networks and devices securely
|
- [**Siemens SINEMA Remote Connect**](https://cache.industry.siemens.com/dl/files/790/109793790/att_1054961/v2/OSS_SINEMA-RC_86.pdf), a remote connectivity solution for monitoring and managing industrial networks and devices securely
|
||||||
- [**Skydio**](https://pages.skydio.com/rs/784-TUF-591/images/Open%20Source%20Software%20Notice%20v0.2.html), a manufacturer of autonomous drones for inspection, public safety, and defense applications
|
|
||||||
- [**Sony PlayStation 4**](https://doc.dl.playstation.net/doc/ps4-oss/index.html), a gaming console developed by Sony that offers a wide range of games and multimedia entertainment features
|
- [**Sony PlayStation 4**](https://doc.dl.playstation.net/doc/ps4-oss/index.html), a gaming console developed by Sony that offers a wide range of games and multimedia entertainment features
|
||||||
- [**Sony Spatial Reality Display**](https://www.sony.co.jp/en/Products/Developer-Spatial-Reality-display/download/dcc-tools/blender-plugin/SpatiaRealityDisplayPluginforPreviewBL_Manual.pdf), a glasses-free stereoscopic 3D display and its plugins for Blender, 3ds Max, and ZBrush
|
|
||||||
- [**Sony Virtual Webcam Driver for Remote Camera**](https://helpguide.sony.net/rc/vwd/v1/zh-cn/print.pdf), a software driver that enables the use of Sony cameras as virtual webcams for video conferencing and streaming
|
- [**Sony Virtual Webcam Driver for Remote Camera**](https://helpguide.sony.net/rc/vwd/v1/zh-cn/print.pdf), a software driver that enables the use of Sony cameras as virtual webcams for video conferencing and streaming
|
||||||
- [**Yamaha Clavinova**](https://usa.yamaha.com/files/download/other_assets/1/2298171/CLP-800_oss_license.pdf), a series of digital pianos combining acoustic piano feel with digital sound technology
|
|
||||||
|
|
||||||
## Operating Systems and Platforms
|
## Operating Systems
|
||||||
|
|
||||||
- [**Apple iOS and macOS**](https://www.apple.com/macos), a family of operating systems developed by Apple, including iOS for mobile devices and macOS for desktop computers
|
- [**Apple iOS and macOS**](https://www.apple.com/macos), a family of operating systems developed by Apple, including iOS for mobile devices and macOS for desktop computers
|
||||||
- [**Chromium**](https://chromium.googlesource.com/chromium/src/+/main/third_party/nlohmann_json/), the open-source browser project that Google Chrome, Microsoft Edge, and many other browsers are built on, where the library is used as data container for on-device model execution
|
|
||||||
- [**Google Fuchsia**](https://fuchsia.googlesource.com/third_party/json/), an open-source operating system developed by Google, designed to be secure, updatable, and adaptable across various devices
|
- [**Google Fuchsia**](https://fuchsia.googlesource.com/third_party/json/), an open-source operating system developed by Google, designed to be secure, updatable, and adaptable across various devices
|
||||||
- [**LG webOS**](https://github.com/webosose/com.webos.service.camera), a Linux-based operating system used in LG smart TVs, signage, and embedded devices
|
|
||||||
- [**Microsoft Azure Linux**](https://github.com/microsoft/azurelinux), a Linux distribution developed by Microsoft for Azure infrastructure and edge workloads
|
|
||||||
- [**OpenHarmony**](https://github.com/openharmony/third_party_json), an open-source operating system for smart devices and the foundation of HarmonyOS
|
|
||||||
- [**SerenityOS**](https://github.com/SerenityOS/serenity), an open-source operating system that aims to provide a simple and beautiful user experience with a focus on simplicity and elegance
|
- [**SerenityOS**](https://github.com/SerenityOS/serenity), an open-source operating system that aims to provide a simple and beautiful user experience with a focus on simplicity and elegance
|
||||||
- [**Windows Subsystem for Linux**](https://github.com/microsoft/WSL), a compatibility layer that runs Linux environments natively on Windows
|
|
||||||
- [**Yocto**](http://ftp.emacinc.com/openembedded-sw/kirkstone-icop-5.15-kirkstone-6.0/archive-2024-10/pn8m-090t-ppc/licenses/nlohmann-json/), a Linux-based build system for creating custom operating systems and software distributions, tailored for embedded devices and IoT applications
|
- [**Yocto**](http://ftp.emacinc.com/openembedded-sw/kirkstone-icop-5.15-kirkstone-6.0/archive-2024-10/pn8m-090t-ppc/licenses/nlohmann-json/), a Linux-based build system for creating custom operating systems and software distributions, tailored for embedded devices and IoT applications
|
||||||
|
|
||||||
## Development Tools and IDEs
|
## Development Tools and IDEs
|
||||||
|
|
||||||
- [**Accentize SpectralBalance**](https://www.accentize.com/products/SpectralBalanceManual.pdf), an adaptive speech analysis tool designed to enhance audio quality by optimizing frequency balance in recordings
|
- [**Accentize SpectralBalance**](https://www.accentize.com/products/SpectralBalanceManual.pdf), an adaptive speech analysis tool designed to enhance audio quality by optimizing frequency balance in recordings
|
||||||
- [**Airbus Ghidralligator**](https://www.cyber.airbus.com/en/newsroom/stories/2025-06-ghidralligator), a Ghidra-based emulator from Airbus CyberSecurity used to fuzz and analyse embedded firmware
|
|
||||||
- [**Apache brpc**](https://github.com/apache/brpc/blob/master/src/butil/iobuf.h), an industrial-grade remote procedure call framework for C++
|
|
||||||
- [**Arm Compiler for Linux**](https://documentation-service.arm.com/static/66558e9d876c8d213b7843e4), a software development toolchain for compiling and optimizing applications on Arm-based Linux systems
|
- [**Arm Compiler for Linux**](https://documentation-service.arm.com/static/66558e9d876c8d213b7843e4), a software development toolchain for compiling and optimizing applications on Arm-based Linux systems
|
||||||
- [**BBEdit**](https://s3.amazonaws.com/BBSW-download/BBEdit_15.1.2_User_Manual.pdf), a professional text and code editor for macOS
|
- [**BBEdit**](https://s3.amazonaws.com/BBSW-download/BBEdit_15.1.2_User_Manual.pdf), a professional text and code editor for macOS
|
||||||
- [**CoderPad**](https://coderpad.io), a collaborative coding platform that enables real-time code interviews and assessments for developers; the library is included in every CoderPad instance and can be accessed with a simple `#include "json.hpp"`
|
- [**CoderPad**](https://coderpad.io), a collaborative coding platform that enables real-time code interviews and assessments for developers; the library is included in every CoderPad instance and can be accessed with a simple `#include "json.hpp"`
|
||||||
- [**Codon**](https://github.com/exaloop/codon/blob/develop/jupyter/jupyter.h), an ahead-of-time compiler for a Python-like language
|
|
||||||
- [**Compiler Explorer**](https://godbolt.org), a web-based tool that allows users to write, compile, and visualize the assembly output of code in various programming languages; the library is readily available and accessible with the directive `#include <nlohmann/json.hpp>`.
|
- [**Compiler Explorer**](https://godbolt.org), a web-based tool that allows users to write, compile, and visualize the assembly output of code in various programming languages; the library is readily available and accessible with the directive `#include <nlohmann/json.hpp>`.
|
||||||
- [**Flutter**](https://github.com/flutter/flutter/blob/master/engine/src/flutter/impeller/compiler/reflector.cc), a UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase
|
- [**GitHub CodeQL**](https://github.com/github/codeql), a code analysis tool used for identifying security vulnerabilities and bugs in software through semantic queries
|
||||||
- [**Fraunhofer VVenC**](https://github.com/fraunhoferhhi/vvenc), a fast and efficient encoder for the Versatile Video Coding (H.266/VVC) standard
|
|
||||||
- [**GitHub CodeQL**](https://github.com/github/codeql/blob/main/shared/cpp/Diagnostics.h), a code analysis tool used for identifying security vulnerabilities and bugs in software through semantic queries
|
|
||||||
- [**GoPro ngfx**](https://github.com/gopro/ngfx), a low-level graphics abstraction and profiling framework developed by GoPro
|
|
||||||
- [**gRPC**](https://github.com/grpc/grpc/blob/master/tools/artifact_gen/utils.h), a high-performance universal remote procedure call framework
|
|
||||||
- [**Hex-Rays**](https://docs.hex-rays.com/user-guide/user-interface/licenses), a reverse engineering toolset for analyzing and decompiling binaries, primarily used for security research and vulnerability analysis
|
- [**Hex-Rays**](https://docs.hex-rays.com/user-guide/user-interface/licenses), a reverse engineering toolset for analyzing and decompiling binaries, primarily used for security research and vulnerability analysis
|
||||||
- [**ImHex**](https://github.com/WerWolv/ImHex), a hex editor designed for reverse engineering, providing advanced features for data analysis and manipulation
|
- [**ImHex**](https://github.com/WerWolv/ImHex), a hex editor designed for reverse engineering, providing advanced features for data analysis and manipulation
|
||||||
- [**Intel GITS**](https://github.com/intel/gits), a tool for capturing and replaying graphics API calls for debugging and performance analysis
|
|
||||||
- [**Intel GPA Framework**](https://intel.github.io/gpasdk-doc/src/licenses.html), a suite of cross-platform tools for capturing, analyzing, and optimizing graphics applications across different APIs
|
- [**Intel GPA Framework**](https://intel.github.io/gpasdk-doc/src/licenses.html), a suite of cross-platform tools for capturing, analyzing, and optimizing graphics applications across different APIs
|
||||||
- [**Intopix**](https://www.intopix.com/software-licensing), a provider of advanced image processing and compression solutions used in software development and AV workflows
|
- [**Intopix**](https://www.intopix.com/software-licensing), a provider of advanced image processing and compression solutions used in software development and AV workflows
|
||||||
- [**Java SE**](https://www.oracle.com/a/tech/docs/jdk8-lium.pdf), the core Java platform that provides the libraries and runtime needed to build and run general-purpose Java applications
|
- [**Java SE**](https://www.oracle.com/a/tech/docs/jdk8-lium.pdf), the core Java platform that provides the libraries and runtime needed to build and run general-purpose Java applications
|
||||||
- [**Meta Yoga**](https://github.com/facebook/yoga), a layout engine that facilitates flexible and efficient user interface design across multiple platforms
|
|
||||||
- [**MKVToolNix**](https://mkvtoolnix.download/doc/README.md), a set of tools for creating, editing, and inspecting MKV (Matroska) multimedia container files
|
- [**MKVToolNix**](https://mkvtoolnix.download/doc/README.md), a set of tools for creating, editing, and inspecting MKV (Matroska) multimedia container files
|
||||||
- [**MRTech IFF SDK**](https://mr-technologies.com/pub/iff-sdk-manual-2-0-1/iff-sdk-manual-2-0-1.pdf), an image processing SDK for machine vision applications with GPU-accelerated pipelines
|
- [**Meta Yoga**](https://github.com/facebook/yoga), a layout engine that facilitates flexible and efficient user interface design across multiple platforms
|
||||||
- [**Nix**](https://github.com/NixOS/nix/blob/master/src/nix/build.cc), a purely functional package manager
|
|
||||||
- [**Notepad++**](https://github.com/notepad-plus-plus/notepad-plus-plus), a free source code editor that supports various programming languages
|
|
||||||
- [**NVIDIA Nsight Compute**](https://docs.nvidia.com/nsight-compute/2022.2/pdf/CopyrightAndLicenses.pdf), a performance analysis tool for CUDA applications that provides detailed insights into GPU performance metrics
|
- [**NVIDIA Nsight Compute**](https://docs.nvidia.com/nsight-compute/2022.2/pdf/CopyrightAndLicenses.pdf), a performance analysis tool for CUDA applications that provides detailed insights into GPU performance metrics
|
||||||
- [**openFrameworks**](https://github.com/openframeworks/openFrameworks/blob/master/libs/openFrameworks/utils/ofJson.h), a community-developed C++ toolkit for creative coding
|
- [**Notepad++**](https://github.com/notepad-plus-plus/notepad-plus-plus), a free source code editor that supports various programming languages
|
||||||
- [**OpenRGB**](https://gitlab.com/CalcProgrammer1/OpenRGB), an open source RGB lighting control that doesn't depend on manufacturer software
|
- [**OpenRGB**](https://gitlab.com/CalcProgrammer1/OpenRGB), an open source RGB lighting control that doesn't depend on manufacturer software
|
||||||
- [**OpenTelemetry C++**](https://github.com/open-telemetry/opentelemetry-cpp), a library for collecting and exporting observability data in C++, enabling developers to implement distributed tracing and metrics in their application
|
- [**OpenTelemetry C++**](https://github.com/open-telemetry/opentelemetry-cpp), a library for collecting and exporting observability data in C++, enabling developers to implement distributed tracing and metrics in their application
|
||||||
- [**Oracle GraalVM**](https://docs.oracle.com/en/graalvm/jdk/21/docs/licensing-information/), a high-performance JDK distribution with ahead-of-time compilation and polyglot runtime support
|
|
||||||
- [**Philips amp-cucumber-cpp-runner**](https://github.com/philips-software/amp-cucumber-cpp-runner), a behaviour-driven development test runner for embedded C++ software developed at Philips
|
|
||||||
- [**Qt Creator**](https://doc.qt.io/qtcreator/qtcreator-attribution-json-nlohmann.html), an IDE for developing applications using the Qt application framework
|
- [**Qt Creator**](https://doc.qt.io/qtcreator/qtcreator-attribution-json-nlohmann.html), an IDE for developing applications using the Qt application framework
|
||||||
- [**Qt for MCUs**](https://doc.qt.io/QtForMCUs/quickultralite-attribution-nlohmann-json.html), a graphics framework for building fluid user interfaces on microcontrollers
|
|
||||||
- [**React Native**](https://github.com/react/react-native/blob/main/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.cpp), a framework for building native mobile applications using React
|
|
||||||
- [**Scanbot SDK**](https://docs.scanbot.io/barcode-scanner-sdk/web/third-party-libraries/), a software development kit (SDK) that provides tools for integrating advanced document scanning and barcode scanning capabilities into applications
|
- [**Scanbot SDK**](https://docs.scanbot.io/barcode-scanner-sdk/web/third-party-libraries/), a software development kit (SDK) that provides tools for integrating advanced document scanning and barcode scanning capabilities into applications
|
||||||
- [**STMicroelectronics TouchGFX**](https://www.st.com/resource/en/additional_license_terms/additional-license-terms-x-cube-touchgfx.html), a graphical user interface framework shipped with STM32 microcontrollers for building embedded HMIs
|
|
||||||
- [**swagger-codegen**](https://github.com/swagger-api/swagger-codegen/blob/master/samples/server/petstore/pistache-server/model/Pet.h), a template-driven engine that generates API clients and server stubs from an OpenAPI specification
|
|
||||||
- [**Swoole**](https://github.com/swoole/swoole-src/blob/master/ext-src/swoole_admin_server.cc), a coroutine-based concurrency engine for PHP
|
|
||||||
- [**Tracy Profiler**](https://github.com/wolfpld/tracy/blob/master/profiler/src/profiler/TracyLlm.hpp), a real-time frame profiler for games and other applications
|
|
||||||
- [**WasmEdge**](https://github.com/WasmEdge/WasmEdge/blob/master/plugins/wasi_nn/GGML/tts/tts_core.cpp), a lightweight WebAssembly runtime for edge and cloud workloads
|
|
||||||
- [**x64dbg**](https://github.com/x64dbg/x64dbg/blob/development/src/cross/remote_table/TableRpcData.h), an open source user mode debugger for Windows, aimed at reverse engineering and malware analysis
|
|
||||||
|
|
||||||
## Machine Learning and AI
|
## Machine Learning and AI
|
||||||
|
|
||||||
- [**Alibaba MNN**](https://github.com/alibaba/MNN), a lightweight deep learning inference engine for mobile and embedded devices
|
|
||||||
- [**AMD Gaia**](https://github.com/amd/gaia), an open-source framework for running generative AI applications locally on AMD hardware
|
|
||||||
- [**AMD Vitis AI (VAIP)**](https://github.com/amd/vaip), the execution provider stack that runs AI models on AMD Ryzen AI and adaptive computing devices
|
|
||||||
- [**Apple Core ML Tools**](https://github.com/apple/coremltools), a set of tools for converting and configuring machine learning models for deployment in Apple's Core ML framework
|
- [**Apple Core ML Tools**](https://github.com/apple/coremltools), a set of tools for converting and configuring machine learning models for deployment in Apple's Core ML framework
|
||||||
- [**Avular Mobile Robotics**](https://www.avular.com/licenses/nlohmann-json-3.9.1.txt), a platform for developing and deploying mobile robotics solutions
|
- [**Avular Mobile Robotics**](https://www.avular.com/licenses/nlohmann-json-3.9.1.txt), a platform for developing and deploying mobile robotics solutions
|
||||||
- [**FunASR**](https://github.com/modelscope/FunASR/blob/main/runtime/http/bin/asr_sessions.h), a speech recognition toolkit for training and deploying end-to-end models
|
|
||||||
- [**Google gemma.cpp**](https://github.com/google/gemma.cpp), a lightweight C++ inference engine designed for running AI models from the Gemma family
|
- [**Google gemma.cpp**](https://github.com/google/gemma.cpp), a lightweight C++ inference engine designed for running AI models from the Gemma family
|
||||||
- [**Google Magenta The Infinite Crate**](https://github.com/magenta/the-infinite-crate), an open-source generative AI plugin for digital audio workstations from Google's Magenta research team
|
|
||||||
- [**GPT4All**](https://github.com/nomic-ai/gpt4all/blob/main/gpt4all-chat/src/tool.h), a desktop application for running local large language models on consumer hardware
|
|
||||||
- [**Huawei MindSpore**](https://github.com/mindspore-ai/mindspore/blob/master/Third_Party_Open_Source_Software_Notice), a deep learning framework for training and inference across device, edge, and cloud
|
|
||||||
- [**KTransformers**](https://github.com/kvcache-ai/ktransformers/blob/main/archive/csrc/balance_serve/sched/model_config.h), a framework for heterogeneous large language model inference
|
|
||||||
- [**llama.cpp**](https://github.com/ggerganov/llama.cpp), a C++ library designed for efficient inference of large language models (LLMs), enabling streamlined integration into applications
|
- [**llama.cpp**](https://github.com/ggerganov/llama.cpp), a C++ library designed for efficient inference of large language models (LLMs), enabling streamlined integration into applications
|
||||||
- [**LocalAI**](https://github.com/mudler/LocalAI/blob/master/backend/cpp/ds4/dsml_renderer.cpp), a self-hosted inference engine that exposes local models through an OpenAI-compatible API
|
|
||||||
- [**MLX**](https://github.com/ml-explore/mlx), an array framework for machine learning on Apple Silicon
|
- [**MLX**](https://github.com/ml-explore/mlx), an array framework for machine learning on Apple Silicon
|
||||||
- [**Mozilla llamafile**](https://github.com/Mozilla-Ocho/llamafile), a tool designed for distributing and executing large language models (LLMs) efficiently using a single file format
|
- [**Mozilla llamafile**](https://github.com/Mozilla-Ocho/llamafile), a tool designed for distributing and executing large language models (LLMs) efficiently using a single file format
|
||||||
- [**NVIDIA ACE**](https://docs.nvidia.com/ace/latest/index.html), a suite of real-time AI solutions designed for the development of interactive avatars and digital human applications, enabling scalable and sophisticated user interactions
|
- [**NVIDIA ACE**](https://docs.nvidia.com/ace/latest/index.html), a suite of real-time AI solutions designed for the development of interactive avatars and digital human applications, enabling scalable and sophisticated user interactions
|
||||||
- [**NVIDIA Instant NGP**](https://github.com/NVlabs/instant-ngp/blob/master/src/nerf_loader.cu), an implementation of instant neural graphics primitives for rapid scene reconstruction
|
|
||||||
- [**NVIDIA TensorRT**](https://github.com/NVIDIA/TensorRT), an SDK for high-performance deep learning inference, including its TensorRT-LLM extension for large language models
|
|
||||||
- [**NVIDIA TensorRT-LLM**](https://github.com/NVIDIA/TensorRT-LLM/blob/main/cpp/tensorrt_llm/common/safetensors.cpp), a toolkit for optimizing and serving large language model inference on GPUs
|
|
||||||
- [**ONNX Runtime**](https://github.com/microsoft/onnxruntime), a cross-platform inference and training accelerator for machine learning models
|
|
||||||
- [**OpenVINO**](https://github.com/openvinotoolkit/openvino), Intel's toolkit for optimizing and deploying deep learning inference across CPUs, GPUs, and NPUs
|
|
||||||
- [**PaddleOCR**](https://github.com/PaddlePaddle/PaddleOCR/blob/main/deploy/cpp_infer/src/modules/text_detection/result.cc), an optical character recognition toolkit that turns documents and images into structured data
|
|
||||||
- [**PaddlePaddle**](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/ap/src/axpr/anf_expr.cc), a deep learning framework for distributed training and inference
|
|
||||||
- [**Peer**](https://support.peer.inc/hc/en-us/articles/17261335054235-Licenses), a platform offering personalized AI assistants for interactive learning and creative collaboration
|
- [**Peer**](https://support.peer.inc/hc/en-us/articles/17261335054235-Licenses), a platform offering personalized AI assistants for interactive learning and creative collaboration
|
||||||
- [**PyTorch**](https://github.com/pytorch/pytorch), a machine learning framework for building and training neural networks, widely used in research and production
|
|
||||||
- [**Qualcomm AI Engine Direct**](https://github.com/qualcomm/qai-appbuilder), a toolchain for building and running generative AI applications on Snapdragon devices
|
|
||||||
- [**sherpa-onnx**](https://github.com/k2-fsa/sherpa-onnx/blob/master/sherpa-onnx/csrc/sentence-piece-tokenizer.cc), a speech toolkit for on-device recognition, synthesis and speaker diarization
|
|
||||||
- [**stable-diffusion.cpp**](https://github.com/leejet/stable-diffusion.cpp), a C++ implementation of the Stable Diffusion image generation model
|
- [**stable-diffusion.cpp**](https://github.com/leejet/stable-diffusion.cpp), a C++ implementation of the Stable Diffusion image generation model
|
||||||
- [**TanvasTouch**](https://tanvas.co/tanvastouch-sdk-third-party-acknowledgments), a software development kit (SDK) that enables developers to create tactile experiences on touchscreens, allowing users to feel textures and physical sensations in a digital environment
|
- [**TanvasTouch**](https://tanvas.co/tanvastouch-sdk-third-party-acknowledgments), a software development kit (SDK) that enables developers to create tactile experiences on touchscreens, allowing users to feel textures and physical sensations in a digital environment
|
||||||
- [**TensorFlow**](https://github.com/tensorflow/tensorflow), a machine learning framework that facilitates the development and training of models, supporting data serialization and efficient data exchange between components
|
- [**TensorFlow**](https://github.com/tensorflow/tensorflow), a machine learning framework that facilitates the development and training of models, supporting data serialization and efficient data exchange between components
|
||||||
- [**whisper.cpp**](https://github.com/ggml-org/whisper.cpp), a C++ implementation of OpenAI's Whisper automatic speech recognition model
|
|
||||||
|
|
||||||
## Scientific Research and Analysis
|
## Scientific Research and Analysis
|
||||||
|
|
||||||
- [**BLACK**](https://www.black-sat.org/en/stable/installation/linux.html), a bounded linear temporal logic (LTL) satisfiability checker
|
- [**BLACK**](https://www.black-sat.org/en/stable/installation/linux.html), a bounded linear temporal logic (LTL) satisfiability checker
|
||||||
- [**CERN ALICE O2**](https://github.com/AliceO2Group/AliceO2), the online-offline computing framework of the ALICE heavy-ion experiment at the Large Hadron Collider
|
|
||||||
- [**CERN Atlas Athena**](https://gitlab.cern.ch/atlas/athena/-/blob/main/Control/PerformanceMonitoring/PerfMonComps/src/PerfMonMTSvc.h), a software framework used in the ATLAS experiment at the Large Hadron Collider (LHC) for performance monitoring
|
- [**CERN Atlas Athena**](https://gitlab.cern.ch/atlas/athena/-/blob/main/Control/PerformanceMonitoring/PerfMonComps/src/PerfMonMTSvc.h), a software framework used in the ATLAS experiment at the Large Hadron Collider (LHC) for performance monitoring
|
||||||
- [**CERN CMSSW**](https://github.com/cms-sw/cmssw), the offline software framework of the CMS experiment at the Large Hadron Collider
|
|
||||||
- [**CERN Gaudi**](https://gitlab.cern.ch/gaudi/Gaudi), the event-processing framework used by the LHCb and ATLAS experiments at the Large Hadron Collider
|
|
||||||
- [**ICU**](https://github.com/unicode-org/icu), the International Components for Unicode, a mature library for software globalization and multilingual support
|
- [**ICU**](https://github.com/unicode-org/icu), the International Components for Unicode, a mature library for software globalization and multilingual support
|
||||||
- [**KAMERA**](https://github.com/Kitware/kamera), a platform for synchronized data collection and real-time deep learning to map marine species like polar bears and seals, aiding Arctic ecosystem research
|
- [**KAMERA**](https://github.com/Kitware/kamera), a platform for synchronized data collection and real-time deep learning to map marine species like polar bears and seals, aiding Arctic ecosystem research
|
||||||
- [**KiCad**](https://gitlab.com/kicad/code/kicad/-/tree/master/thirdparty/nlohmann_json), a free and open-source software suite for electronic design automation
|
- [**KiCad**](https://gitlab.com/kicad/code/kicad/-/tree/master/thirdparty/nlohmann_json), a free and open-source software suite for electronic design automation
|
||||||
- [**LLNL ROSE**](https://github.com/llnl/rose), a compiler infrastructure from Lawrence Livermore National Laboratory for building source-to-source program analysis and transformation tools
|
|
||||||
- [**Maple**](https://www.maplesoft.com/support/help/Maple/view.aspx?path=copyright), a symbolic and numeric computing environment for advanced mathematical modeling and analysis
|
- [**Maple**](https://www.maplesoft.com/support/help/Maple/view.aspx?path=copyright), a symbolic and numeric computing environment for advanced mathematical modeling and analysis
|
||||||
- [**MeVisLab**](https://mevislabdownloads.mevis.de/docs/current/MeVis/ThirdParty/Documentation/Publish/ThirdPartyReference/index.html), a software framework for medical image processing and visualization.
|
- [**MeVisLab**](https://mevislabdownloads.mevis.de/docs/current/MeVis/ThirdParty/Documentation/Publish/ThirdPartyReference/index.html), a software framework for medical image processing and visualization.
|
||||||
- [**MITK**](https://github.com/MITK/MITK), the Medical Imaging Interaction Toolkit, a framework for developing interactive medical image processing software
|
|
||||||
- [**OpenPMD API**](https://openpmd-api.readthedocs.io/en/0.8.0-alpha/backends/json.html), a versatile programming interface for accessing and managing scientific data, designed to facilitate the efficient storage, retrieval, and sharing of simulation data across various applications and platforms
|
- [**OpenPMD API**](https://openpmd-api.readthedocs.io/en/0.8.0-alpha/backends/json.html), a versatile programming interface for accessing and managing scientific data, designed to facilitate the efficient storage, retrieval, and sharing of simulation data across various applications and platforms
|
||||||
- [**ORNL DataFed**](https://github.com/ORNL/DataFed), a federated scientific data management system developed at Oak Ridge National Laboratory
|
|
||||||
- [**ParaView**](https://github.com/Kitware/ParaView), an open-source tool for large-scale data visualization and analysis across various scientific domains
|
- [**ParaView**](https://github.com/Kitware/ParaView), an open-source tool for large-scale data visualization and analysis across various scientific domains
|
||||||
- [**QGIS**](https://gitlab.b-data.ch/qgis/qgis/-/blob/backport-57658-to-release-3_34/external/nlohmann/json.hpp), a free and open-source geographic information system (GIS) application that allows users to create, edit, visualize, and analyze geospatial data across a variety of formats
|
- [**QGIS**](https://gitlab.b-data.ch/qgis/qgis/-/blob/backport-57658-to-release-3_34/external/nlohmann/json.hpp), a free and open-source geographic information system (GIS) application that allows users to create, edit, visualize, and analyze geospatial data across a variety of formats
|
||||||
- [**Sandia InterSpec**](https://github.com/sandialabs/InterSpec), spectral radiation analysis software from Sandia National Laboratories for identifying radioactive isotopes
|
|
||||||
- [**VolView**](https://github.com/Kitware/VolView), a lightweight application for interactive visualization and analysis of 3D medical imaging data.
|
|
||||||
- [**VTK**](https://github.com/Kitware/VTK), a software library for 3D computer graphics, image processing, and visualization
|
- [**VTK**](https://github.com/Kitware/VTK), a software library for 3D computer graphics, image processing, and visualization
|
||||||
|
- [**VolView**](https://github.com/Kitware/VolView), a lightweight application for interactive visualization and analysis of 3D medical imaging data.
|
||||||
|
|
||||||
## Business and Productivity Software
|
## Business and Productivity Software
|
||||||
|
|
||||||
- [**ArcGIS PRO**](https://www.esri.com/content/dam/esrisites/en-us/media/legal/open-source-acknowledgements/arcgis-pro-2-8-attribution-report.html), a desktop geographic information system (GIS) application developed by Esri for mapping and spatial analysis
|
- [**ArcGIS PRO**](https://www.esri.com/content/dam/esrisites/en-us/media/legal/open-source-acknowledgements/arcgis-pro-2-8-attribution-report.html), a desktop geographic information system (GIS) application developed by Esri for mapping and spatial analysis
|
||||||
- [**Autodesk Desktop**](https://damassets.autodesk.net/content/dam/autodesk/www/Company/legal-notices-trademarks/autodesk-desktop-platform-components/internal-autodesk-components-web-page-2023.pdf), a software platform developed by Autodesk for creating and managing desktop applications and services
|
- [**Autodesk Desktop**](https://damassets.autodesk.net/content/dam/autodesk/www/Company/legal-notices-trademarks/autodesk-desktop-platform-components/internal-autodesk-components-web-page-2023.pdf), a software platform developed by Autodesk for creating and managing desktop applications and services
|
||||||
- [**Check Point**](https://www.checkpoint.com/about-us/copyright-and-trademarks/), a cybersecurity company specializing in threat prevention and network security solutions, offering a range of products designed to protect enterprises from cyber threats and ensure data integrity
|
- [**Check Point**](https://www.checkpoint.com/about-us/copyright-and-trademarks/), a cybersecurity company specializing in threat prevention and network security solutions, offering a range of products designed to protect enterprises from cyber threats and ensure data integrity
|
||||||
- [**EasyEffects**](https://github.com/wwmm/easyeffects/blob/master/src/presets_manager.hpp), an audio effects processor for PipeWire offering limiting, compression and equalization
|
|
||||||
- [**espanso**](https://github.com/espanso/espanso/blob/dev/espanso-ui/src/win32/native.cpp), a cross-platform text expander
|
|
||||||
- [**Karabiner-Elements**](https://github.com/pqrs-org/Karabiner-Elements/blob/main/src/share/app_icon.hpp), a keyboard customizer for macOS
|
|
||||||
- [**MacType**](https://github.com/snowie2000/mactype/blob/directwrite/settings.h), a font rendering engine for Windows
|
|
||||||
- [**magicplan**](https://help.magicplan.app/acknowledgments), a mobile application for creating floor plans and interior designs using augmented reality
|
|
||||||
- [**Microsoft Office for Mac**](https://officecdnmac.microsoft.com/pr/legal/mac/OfficeforMacAttributions.html), a suite of productivity applications developed by Microsoft for macOS, including tools for word processing, spreadsheets, and presentations
|
- [**Microsoft Office for Mac**](https://officecdnmac.microsoft.com/pr/legal/mac/OfficeforMacAttributions.html), a suite of productivity applications developed by Microsoft for macOS, including tools for word processing, spreadsheets, and presentations
|
||||||
- [**Microsoft Teams**](https://www.microsoft.com/microsoft-teams/), a team collaboration application offering workspace chat and video conferencing, file storage, and integration of proprietary and third-party applications and services
|
- [**Microsoft Teams**](https://www.microsoft.com/microsoft-teams/), a team collaboration application offering workspace chat and video conferencing, file storage, and integration of proprietary and third-party applications and services
|
||||||
- [**MuseScore**](https://github.com/musescore/MuseScore), a free and open-source music notation and composition application
|
|
||||||
- [**NanaZip**](https://github.com/M2Team/NanaZip/blob/main/NanaZip.Codecs/NanaZip.Codecs.Archive.ElectronAsar.cpp), a 7-Zip derivative built for modern Windows
|
|
||||||
- [**Nexthink Infinity**](https://docs.nexthink.com/legal/services-terms/experience-open-source-software-licenses/infinity-2022.8-software-licenses), a digital employee experience management platform for monitoring and improving IT performance
|
- [**Nexthink Infinity**](https://docs.nexthink.com/legal/services-terms/experience-open-source-software-licenses/infinity-2022.8-software-licenses), a digital employee experience management platform for monitoring and improving IT performance
|
||||||
- [**Sophos Connect Client**](https://docs.sophos.com/nsg/licenses/SophosConnect/SophosConnectAttribution.html), a secure VPN client from Sophos that allows remote users to connect to their corporate network, ensuring secure access to resources and data
|
- [**Sophos Connect Client**](https://docs.sophos.com/nsg/licenses/SophosConnect/SophosConnectAttribution.html), a secure VPN client from Sophos that allows remote users to connect to their corporate network, ensuring secure access to resources and data
|
||||||
- [**Stonebranch**](https://stonebranchdocs.atlassian.net/wiki/spaces/UA77/pages/799545647/Licenses+for+Third-Party+Libraries), a cloud-based cybersecurity solution that integrates backup, disaster recovery, and cybersecurity features to protect data and ensure business continuity for organizations
|
- [**Stonebranch**](https://stonebranchdocs.atlassian.net/wiki/spaces/UA77/pages/799545647/Licenses+for+Third-Party+Libraries), a cloud-based cybersecurity solution that integrates backup, disaster recovery, and cybersecurity features to protect data and ensure business continuity for organizations
|
||||||
- [**Tablecruncher**](https://tablecruncher.com/), a data analysis tool that allows users to import, analyze, and visualize spreadsheet data, offering interactive features for better insights and decision-making
|
- [**Tablecruncher**](https://tablecruncher.com/), a data analysis tool that allows users to import, analyze, and visualize spreadsheet data, offering interactive features for better insights and decision-making
|
||||||
- [**VNote**](https://github.com/vnotex/vnote/blob/master/src/core/services/notebookcoreservice.cpp), a Markdown-based note-taking application written in C++
|
- [**magicplan**](https://help.magicplan.app/acknowledgments), a mobile application for creating floor plans and interior designs using augmented reality
|
||||||
|
|
||||||
## Databases and Big Data
|
## Databases and Big Data
|
||||||
|
|
||||||
- [**ADIOS2**](https://code.ornl.gov/ecpcitest/adios2/-/tree/pr4285_FFSUpstream/thirdparty/nlohmann_json?ref_type=heads), a data management framework designed for high-performance input and output operations
|
- [**ADIOS2**](https://code.ornl.gov/ecpcitest/adios2/-/tree/pr4285_FFSUpstream/thirdparty/nlohmann_json?ref_type=heads), a data management framework designed for high-performance input and output operations
|
||||||
- [**Apache Doris**](https://github.com/apache/doris/blob/master/be/src/runtime/be_proc_monitor.cpp), a real-time analytical database for high-concurrency queries
|
|
||||||
- [**Claris FileMaker Server**](https://www.claris.com/company/legal/docs/acknowledgements/filemaker-server-macwin/claris_fms2025_acknowledgements_en.pdf), the server platform hosting FileMaker custom apps and databases, developed by Apple subsidiary Claris
|
|
||||||
- [**ClickHouse**](https://github.com/ClickHouse/ClickHouse), a column-oriented database management system for real-time analytical queries
|
|
||||||
- [**Cribl Stream**](https://docs.cribl.io/stream/third-party-current-list/), a real-time data processing platform that enables organizations to collect, route, and transform observability data, enhancing visibility and insights into their systems
|
- [**Cribl Stream**](https://docs.cribl.io/stream/third-party-current-list/), a real-time data processing platform that enables organizations to collect, route, and transform observability data, enhancing visibility and insights into their systems
|
||||||
- [**DB Browser for SQLite**](https://github.com/sqlitebrowser/sqlitebrowser), a visual open-source tool for creating, designing, and editing SQLite database files
|
- [**DB Browser for SQLite**](https://github.com/sqlitebrowser/sqlitebrowser), a visual open-source tool for creating, designing, and editing SQLite database files
|
||||||
- [**Manticore Search**](https://github.com/manticoresoftware/manticoresearch/blob/main/src/searchdhttpcompat.cpp), a database for search, offering full-text and vector queries
|
|
||||||
- [**Milvus**](https://github.com/milvus-io/milvus/blob/master/internal/core/src/query/PlanImpl.h), a cloud-native vector database built for embedding similarity search
|
|
||||||
- [**MongoDB**](https://github.com/mongodb/mongo/blob/master/src/mongo/replay/config_handler.cpp), a general-purpose document database
|
|
||||||
- [**MySQL Connector/C++**](https://docs.oracle.com/cd/E17952_01/connector-cpp-9.1-license-com-en/license-opentelemetry-cpp-com.html), a C++ library for connecting and interacting with MySQL databases
|
- [**MySQL Connector/C++**](https://docs.oracle.com/cd/E17952_01/connector-cpp-9.1-license-com-en/license-opentelemetry-cpp-com.html), a C++ library for connecting and interacting with MySQL databases
|
||||||
- [**MySQL NDB Cluster**](https://downloads.mysql.com/docs/licenses/cluster-9.0-com-en.pdf), a distributed database system that provides high availability and scalability for MySQL databases
|
- [**MySQL NDB Cluster**](https://downloads.mysql.com/docs/licenses/cluster-9.0-com-en.pdf), a distributed database system that provides high availability and scalability for MySQL databases
|
||||||
- [**MySQL Shell**](https://downloads.mysql.com/docs/licenses/mysql-shell-8.0-gpl-en.pdf), an advanced client and code editor for interacting with MySQL servers, supporting SQL, Python, and JavaScript
|
- [**MySQL Shell**](https://downloads.mysql.com/docs/licenses/mysql-shell-8.0-gpl-en.pdf), an advanced client and code editor for interacting with MySQL servers, supporting SQL, Python, and JavaScript
|
||||||
- [**PrestoDB**](https://github.com/prestodb/presto/blob/master/presto-native-execution/presto_cpp/main/Announcer.cpp), a distributed SQL query engine designed for large-scale data analytics, originally developed by Facebook
|
- [**PrestoDB**](https://github.com/prestodb/presto), a distributed SQL query engine designed for large-scale data analytics, originally developed by Facebook
|
||||||
- [**ROOT Data Analysis Framework**](https://root.cern/doc/v614/classnlohmann_1_1basic__json.html), an open-source data analysis framework widely used in high-energy physics and other fields for data processing and visualization
|
- [**ROOT Data Analysis Framework**](https://root.cern/doc/v614/classnlohmann_1_1basic__json.html), an open-source data analysis framework widely used in high-energy physics and other fields for data processing and visualization
|
||||||
- [**Typesense**](https://github.com/typesense/typesense/blob/v31/include/join.h), an open source typo-tolerant search engine
|
|
||||||
- [**Vearch**](https://github.com/jd-opensource/vearch), a distributed vector database developed at JD.com for similarity search and retrieval-augmented generation
|
|
||||||
- [**WiredTiger**](https://github.com/wiredtiger/wiredtiger), a high-performance storage engine for databases, offering support for compression, concurrency, and checkpointing
|
- [**WiredTiger**](https://github.com/wiredtiger/wiredtiger), a high-performance storage engine for databases, offering support for compression, concurrency, and checkpointing
|
||||||
|
|
||||||
## Simulation and Modeling
|
## Simulation and Modeling
|
||||||
|
|
||||||
- [**Adobe Lagrange**](https://github.com/adobe/lagrange), a geometry processing library developed by Adobe for mesh manipulation and analysis
|
|
||||||
- [**Arcturus HoloSuite**](https://www.datocms-assets.com/104353/1698904597-holosuite-third-party-software-credits-and-attributions-2.pdf), a software toolset for capturing, editing, and streaming volumetric video, featuring advanced compression technologies for high-quality 3D content creation
|
- [**Arcturus HoloSuite**](https://www.datocms-assets.com/104353/1698904597-holosuite-third-party-software-credits-and-attributions-2.pdf), a software toolset for capturing, editing, and streaming volumetric video, featuring advanced compression technologies for high-quality 3D content creation
|
||||||
- [**azul**](https://pure.tudelft.nl/ws/files/85338589/tgis.12673.pdf), a fast and efficient 3D city model viewer designed for visualizing urban environments and spatial data
|
- [**azul**](https://pure.tudelft.nl/ws/files/85338589/tgis.12673.pdf), a fast and efficient 3D city model viewer designed for visualizing urban environments and spatial data
|
||||||
- [**Bambu Studio**](https://github.com/bambulab/BambuStudio), a slicing and print management application for Bambu Lab 3D printers
|
|
||||||
- [**Blender**](https://projects.blender.org/blender/blender/search?q=nlohmann), a free and open-source 3D creation suite for modeling, animation, rendering, and more
|
- [**Blender**](https://projects.blender.org/blender/blender/search?q=nlohmann), a free and open-source 3D creation suite for modeling, animation, rendering, and more
|
||||||
- [**cpplot**](https://cpplot.readthedocs.io/en/latest/library_api/function_eigen_8h_1ac080eac0541014c5892a55e41bf785e6.html), a library for creating interactive graphs and charts in C++, which can be viewed in web browsers
|
- [**cpplot**](https://cpplot.readthedocs.io/en/latest/library_api/function_eigen_8h_1ac080eac0541014c5892a55e41bf785e6.html), a library for creating interactive graphs and charts in C++, which can be viewed in web browsers
|
||||||
- [**Foundry Nuke**](https://learn.foundry.com/nuke/content/misc/studio_third_party_libraries.html), a powerful node-based digital compositing and visual effects application used in film and television post-production
|
- [**Foundry Nuke**](https://learn.foundry.com/nuke/content/misc/studio_third_party_libraries.html), a powerful node-based digital compositing and visual effects application used in film and television post-production
|
||||||
- [**FreeCAD**](https://github.com/FreeCAD/FreeCAD), a free and open-source parametric 3D CAD modeler for product design and engineering
|
|
||||||
- [**GAMS**](https://www.gams.com/47/docs/THIRDPARTY.html), a high-performance mathematical modeling system for optimization and decision support
|
- [**GAMS**](https://www.gams.com/47/docs/THIRDPARTY.html), a high-performance mathematical modeling system for optimization and decision support
|
||||||
- [**Keysight WirelessPro**](https://docs.keysight.com/display/engdocwirelesspro/WirelessPro+2026+Release+Notes), a simulation platform for 5G, 5G-Advanced, and 6G cellular network research
|
|
||||||
- [**Kitware SMTK**](https://github.com/Kitware/SMTK), a software toolkit for managing simulation models and workflows in scientific and engineering applications
|
- [**Kitware SMTK**](https://github.com/Kitware/SMTK), a software toolkit for managing simulation models and workflows in scientific and engineering applications
|
||||||
- [**M-Star**](https://docs.mstarcfd.com/3_Licensing/thirdparty-licenses.html), a computational fluid dynamics software for simulating and analyzing fluid flow
|
- [**M-Star**](https://docs.mstarcfd.com/3_Licensing/thirdparty-licenses.html), a computational fluid dynamics software for simulating and analyzing fluid flow
|
||||||
- [**MapleSim CAD Toolbox**](https://www.maplesoft.com/support/help/MapleSim/view.aspx?path=CADToolbox/copyright), a software extension for MapleSim that integrates CAD models, allowing users to import, manipulate, and analyze 3D CAD data within the MapleSim environment for enhanced modeling and simulation
|
- [**MapleSim CAD Toolbox**](https://www.maplesoft.com/support/help/MapleSim/view.aspx?path=CADToolbox/copyright), a software extension for MapleSim that integrates CAD models, allowing users to import, manipulate, and analyze 3D CAD data within the MapleSim environment for enhanced modeling and simulation
|
||||||
- [**Microsoft AirSim**](https://github.com/microsoft/AirSim/blob/main/AirLib/include/common/Settings.hpp), a simulator for autonomous vehicles and drones built on Unreal Engine
|
|
||||||
- [**NVIDIA Omniverse**](https://docs.omniverse.nvidia.com/composer/latest/common/product-licenses/usd-explorer/usd-explorer-2023.2.0-licenses-manifest.html), a platform for 3D content creation and collaboration that enables real-time simulations and interactive experiences across various industries
|
- [**NVIDIA Omniverse**](https://docs.omniverse.nvidia.com/composer/latest/common/product-licenses/usd-explorer/usd-explorer-2023.2.0-licenses-manifest.html), a platform for 3D content creation and collaboration that enables real-time simulations and interactive experiences across various industries
|
||||||
- [**OpenSCAD**](https://github.com/openscad/openscad/blob/master/src/core/AIClient.cc), a script-driven solid 3D CAD modeller
|
|
||||||
- [**OrcaSlicer**](https://github.com/SoftFever/OrcaSlicer), an open-source slicer supporting a wide range of consumer 3D printers
|
|
||||||
- [**Pixar Renderman**](https://rmanwiki-26.pixar.com/space/REN26/19662083/Legal+Notice), a photorealistic 3D rendering software developed by Pixar, widely used in the film industry for creating high-quality visual effects and animations
|
- [**Pixar Renderman**](https://rmanwiki-26.pixar.com/space/REN26/19662083/Legal+Notice), a photorealistic 3D rendering software developed by Pixar, widely used in the film industry for creating high-quality visual effects and animations
|
||||||
- [**PrusaSlicer**](https://github.com/prusa3d/PrusaSlicer), the slicing software developed by Prusa Research for its 3D printers
|
|
||||||
- [**ROS - Robot Operating System**](http://docs.ros.org/en/noetic/api/behaviortree_cpp/html/json_8hpp_source.html), a set of software libraries and tools that assist in developing robot applications
|
- [**ROS - Robot Operating System**](http://docs.ros.org/en/noetic/api/behaviortree_cpp/html/json_8hpp_source.html), a set of software libraries and tools that assist in developing robot applications
|
||||||
- [**UBS**](https://www.ubs.com/), a multinational financial services and banking company
|
- [**UBS**](https://www.ubs.com/), a multinational financial services and banking company
|
||||||
|
|
||||||
@@ -278,31 +161,18 @@ the result of an internet search. If you know further customers of the library,
|
|||||||
- [**Acronis Cyber Protect Cloud**](https://care.acronis.com/s/article/59533-Third-party-software-used-in-Acronis-Cyber-Protect-Cloud?language=en_US), an all-in-one data protection solution that combines backup, disaster recovery, and cybersecurity to safeguard business data from threats like ransomware
|
- [**Acronis Cyber Protect Cloud**](https://care.acronis.com/s/article/59533-Third-party-software-used-in-Acronis-Cyber-Protect-Cloud?language=en_US), an all-in-one data protection solution that combines backup, disaster recovery, and cybersecurity to safeguard business data from threats like ransomware
|
||||||
- [**Baereos**](https://gitlab.tiger-computing.co.uk/packages/bareos/-/blob/tiger/bullseye/third-party/CLI11/examples/json.cpp), a backup solution that provides data protection and recovery options for various environments, including physical and virtual systems
|
- [**Baereos**](https://gitlab.tiger-computing.co.uk/packages/bareos/-/blob/tiger/bullseye/third-party/CLI11/examples/json.cpp), a backup solution that provides data protection and recovery options for various environments, including physical and virtual systems
|
||||||
- [**Bitdefender Home Scanner**](https://www.bitdefender.de/site/Main/view/home-scanner-open-source.html), a tool from Bitdefender that scans devices for malware and security threats, providing a safeguard against potential online dangers
|
- [**Bitdefender Home Scanner**](https://www.bitdefender.de/site/Main/view/home-scanner-open-source.html), a tool from Bitdefender that scans devices for malware and security threats, providing a safeguard against potential online dangers
|
||||||
- [**Cisco MLS++**](https://github.com/cisco/mlspp), an implementation of the Messaging Layer Security protocol for end-to-end encrypted group messaging
|
|
||||||
- [**Citrix Provisioning**](https://docs.citrix.com/en-us/provisioning/2203-ltsr/downloads/pvs-third-party-notices-2203.pdf), a solution that streamlines the delivery of virtual desktops and applications by allowing administrators to manage and provision resources efficiently across multiple environments
|
- [**Citrix Provisioning**](https://docs.citrix.com/en-us/provisioning/2203-ltsr/downloads/pvs-third-party-notices-2203.pdf), a solution that streamlines the delivery of virtual desktops and applications by allowing administrators to manage and provision resources efficiently across multiple environments
|
||||||
- [**Citrix Virtual Apps and Desktops**](https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/2305/downloads/third-party-notices-apps-and-desktops.pdf), a solution from Citrix that delivers virtual apps and desktops
|
- [**Citrix Virtual Apps and Desktops**](https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/2305/downloads/third-party-notices-apps-and-desktops.pdf), a solution from Citrix that delivers virtual apps and desktops
|
||||||
- [**Cyberarc**](https://docs.cyberark.com/Downloads/Legal/Privileged%20Session%20Manager%20for%20SSH%20Third-Party%20Notices.pdf), a security solution that specializes in privileged access management, enabling organizations to control and monitor access to critical systems and data, thereby enhancing overall cybersecurity posture
|
- [**Cyberarc**](https://docs.cyberark.com/Downloads/Legal/Privileged%20Session%20Manager%20for%20SSH%20Third-Party%20Notices.pdf), a security solution that specializes in privileged access management, enabling organizations to control and monitor access to critical systems and data, thereby enhancing overall cybersecurity posture
|
||||||
- [**Deutsche Telekom sysrepo-plugins**](https://github.com/telekom/sysrepo-plugins), a collection of YANG datastore plugins used to manage network devices
|
|
||||||
- [**Egnyte Desktop**](https://helpdesk.egnyte.com/hc/en-us/articles/360007071732-Third-Party-Software-Acknowledgements), a secure cloud storage solution designed for businesses, enabling file sharing, collaboration, and data management across teams while ensuring compliance and data protection
|
- [**Egnyte Desktop**](https://helpdesk.egnyte.com/hc/en-us/articles/360007071732-Third-Party-Software-Acknowledgements), a secure cloud storage solution designed for businesses, enabling file sharing, collaboration, and data management across teams while ensuring compliance and data protection
|
||||||
- [**Elster**](https://www.secunet.com/en/about-us/press/article/elstersecure-bietet-komfortablen-login-ohne-passwort-dank-secunet-protect4use), a digital platform developed by German tax authorities for secure and efficient electronic tax filing and management using secunet protect4use
|
- [**Elster**](https://www.secunet.com/en/about-us/press/article/elstersecure-bietet-komfortablen-login-ohne-passwort-dank-secunet-protect4use), a digital platform developed by German tax authorities for secure and efficient electronic tax filing and management using secunet protect4use
|
||||||
- [**Envoy**](https://github.com/envoyproxy/envoy), a cloud-native edge and service proxy that forms the data plane of many service meshes
|
|
||||||
- [**Ethereum Solidity**](https://github.com/ethereum/solidity), a high-level, object-oriented programming language designed for implementing smart contracts on the Ethereum platform
|
- [**Ethereum Solidity**](https://github.com/ethereum/solidity), a high-level, object-oriented programming language designed for implementing smart contracts on the Ethereum platform
|
||||||
- [**gVisor**](https://github.com/google/gvisor), an application kernel that provides a secure sandbox for running untrusted containers
|
|
||||||
- [**IBM Storage Virtualize**](https://public.dhe.ibm.com/systems/support/warranty/pdfs/stgoilc/SV_for_FS_7300_v8_7_0_Base_OILC.pdf), the software powering IBM FlashSystem enterprise storage arrays
|
|
||||||
- [**Inciga**](https://fossies.org/linux/icinga2/third-party/nlohmann_json/json.hpp), a monitoring tool for IT infrastructure, designed to provide insights into system performance and availability through customizable dashboards and alerts
|
- [**Inciga**](https://fossies.org/linux/icinga2/third-party/nlohmann_json/json.hpp), a monitoring tool for IT infrastructure, designed to provide insights into system performance and availability through customizable dashboards and alerts
|
||||||
- [**Intel Accelerator Management Daemon for VMware ESXi**](https://downloadmirror.intel.com/772507/THIRD-PARTY.txt), a management tool designed for monitoring and controlling Intel hardware accelerators within VMware ESXi environments, optimizing performance and resource allocation
|
- [**Intel Accelerator Management Daemon for VMware ESXi**](https://downloadmirror.intel.com/772507/THIRD-PARTY.txt), a management tool designed for monitoring and controlling Intel hardware accelerators within VMware ESXi environments, optimizing performance and resource allocation
|
||||||
- [**Juniper Identity Management Service**](https://www.juniper.net/documentation/us/en/software/jims/jims-guide/jims-guide.pdf)
|
- [**Juniper Identity Management Service**](https://www.juniper.net/documentation/us/en/software/jims/jims-guide/jims-guide.pdf)
|
||||||
- [**Meta FBOSS**](https://github.com/facebook/fboss), the software stack that controls the network switches in Meta's data centers
|
|
||||||
- [**Microsoft Azure IoT SDK**](https://library.e.abb.com/public/2779c5f85f30484192eb3cb3f666a201/IP%20Gateway%20Open%20License%20Declaration_9AKK108467A4095_Rev_C.pdf), a collection of tools and libraries to help developers connect, build, and deploy Internet of Things (IoT) solutions on the Azure cloud platform
|
- [**Microsoft Azure IoT SDK**](https://library.e.abb.com/public/2779c5f85f30484192eb3cb3f666a201/IP%20Gateway%20Open%20License%20Declaration_9AKK108467A4095_Rev_C.pdf), a collection of tools and libraries to help developers connect, build, and deploy Internet of Things (IoT) solutions on the Azure cloud platform
|
||||||
- [**Microsoft Confidential Consortium Framework**](https://github.com/microsoft/CCF), a framework for building secure, highly available applications on trusted execution environments
|
|
||||||
- [**Microsoft WinGet**](https://github.com/microsoft/winget-cli), a command-line utility included in the Windows Package Manager
|
- [**Microsoft WinGet**](https://github.com/microsoft/winget-cli), a command-line utility included in the Windows Package Manager
|
||||||
- [**Mitsubishi Electric SECS/GEM**](https://dl.mitsubishielectric.com/dl/fa/document/manual/plc/sh082483eng/sh082483engi.pdf), the semiconductor equipment communication software running on Mitsubishi Electric C Controller and C intelligent function modules
|
|
||||||
- [**Moxa**](https://www.moxa.com/getmedia/fbe2a0c7-8dda-4b5b-a501-15e45adebb1f/moxa-foss-statement-for-da-720-series-win-10-ltsc-21h2-declaration-v1.0.pdf), a provider of industrial networking, computing, and automation infrastructure
|
|
||||||
- [**plexusAV**](https://www.sisme.com/media/10994/manual_plexusav-p-avn-4-form8244-c.pdf), a high-performance AV-over-IP transceiver device capable of video encoding and decoding using the IPMX standard
|
- [**plexusAV**](https://www.sisme.com/media/10994/manual_plexusav-p-avn-4-form8244-c.pdf), a high-performance AV-over-IP transceiver device capable of video encoding and decoding using the IPMX standard
|
||||||
- [**Pointr**](https://docs-dev.pointr.tech/docs/8.x/Developer%20Portal/Open%20Source%20Licenses/), a platform for indoor positioning and navigation solutions, offering tools and SDKs for developers to create location-based applications
|
- [**Pointr**](https://docs-dev.pointr.tech/docs/8.x/Developer%20Portal/Open%20Source%20Licenses/), a platform for indoor positioning and navigation solutions, offering tools and SDKs for developers to create location-based applications
|
||||||
- [**secunet protect4use**](https://www.secunet.com/en/about-us/press/article/elstersecure-bietet-komfortablen-login-ohne-passwort-dank-secunet-protect4use), a secure, passwordless multifactor authentication solution that transforms smartphones into digital keyrings, ensuring high security for online services and digital identities
|
- [**secunet protect4use**](https://www.secunet.com/en/about-us/press/article/elstersecure-bietet-komfortablen-login-ohne-passwort-dank-secunet-protect4use), a secure, passwordless multifactor authentication solution that transforms smartphones into digital keyrings, ensuring high security for online services and digital identities
|
||||||
- [**Sencore MRD 7000**](https://www.foccusdigital.com/wp-content/uploads/2025/03/MRD-7000-Manual-8175V.pdf), a professional multi-channel receiver and decoder supporting UHD and HD stream decoding
|
- [**Sencore MRD 7000**](https://www.foccusdigital.com/wp-content/uploads/2025/03/MRD-7000-Manual-8175V.pdf), a professional multi-channel receiver and decoder supporting UHD and HD stream decoding
|
||||||
- [**Siemens SINEC**](https://cache.industry.siemens.com/dl/files/917/109974917/att_1298783/v2/OSS_SINEC-NMS_99.pdf), a family of network management and infrastructure services for industrial networks
|
|
||||||
- [**Toshiba Industrial Servers**](https://www.global.toshiba/content/dam/toshiba/jp/products-solutions/industrial/computer/product/server/fs20000r/pdf/FS20000R_OSS_License_6E8C5817_rev0.pdf), the FS20000R series of industrial servers for factory automation and control systems
|
|
||||||
- [**Wazuh**](https://github.com/wazuh/wazuh/blob/main/src/data_provider/src/sysInfo.cpp), a security platform for threat detection, integrity monitoring and incident response
|
|
||||||
- [**ZeroTier**](https://github.com/zerotier/ZeroTierOne/blob/dev/osdep/OSUtils.hpp), a software-defined networking service that creates virtual Ethernet networks
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1001 KiB After Width: | Height: | Size: 1.3 MiB |
@@ -98,6 +98,7 @@ nav:
|
|||||||
- Types:
|
- Types:
|
||||||
- features/types/index.md
|
- features/types/index.md
|
||||||
- features/types/number_handling.md
|
- features/types/number_handling.md
|
||||||
|
- features/types/template_parameters.md
|
||||||
- Integration:
|
- Integration:
|
||||||
- integration/index.md
|
- integration/index.md
|
||||||
- integration/migration_guide.md
|
- integration/migration_guide.md
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
wheel==0.48.0
|
wheel==0.48.0
|
||||||
|
|
||||||
mkdocs==1.6.1 # documentation framework
|
mkdocs==1.6.1 # documentation framework
|
||||||
mkdocs-git-revision-date-localized-plugin==1.5.4 # plugin "git-revision-date-localized"
|
mkdocs-git-revision-date-localized-plugin==1.5.3 # plugin "git-revision-date-localized"
|
||||||
mkdocs-material==9.7.7 # theme for mkdocs
|
mkdocs-material==9.7.7 # theme for mkdocs
|
||||||
mkdocs-material-extensions==1.3.1 # extensions
|
mkdocs-material-extensions==1.3.1 # extensions
|
||||||
mkdocs-minify-plugin==0.8.0 # plugin "minify"
|
mkdocs-minify-plugin==0.8.0 # plugin "minify"
|
||||||
|
|||||||
@@ -101,7 +101,10 @@ class exception : public std::exception
|
|||||||
{
|
{
|
||||||
if (&element.second == current)
|
if (&element.second == current)
|
||||||
{
|
{
|
||||||
tokens.emplace_back(element.first.c_str());
|
// data() is null-terminated, so a key containing
|
||||||
|
// a null byte is cut short here rather than
|
||||||
|
// truncating the whole message at what()
|
||||||
|
tokens.emplace_back(element.first.data());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,9 @@ std::size_t hash(const BasicJsonType& j)
|
|||||||
seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));
|
seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));
|
||||||
for (const auto byte : j.get_binary())
|
for (const auto byte : j.get_binary())
|
||||||
{
|
{
|
||||||
seed = combine(seed, std::hash<std::uint8_t> {}(byte));
|
// the cast is needed for binary types whose value type is not
|
||||||
|
// an integer (e.g., std::byte)
|
||||||
|
seed = combine(seed, std::hash<std::uint8_t> {}(static_cast<std::uint8_t>(byte)));
|
||||||
}
|
}
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2899,7 +2899,10 @@ class binary_reader
|
|||||||
number_string,
|
number_string,
|
||||||
out_of_range::create(406, concat("number overflow parsing '", number_string, '\''), nullptr));
|
out_of_range::create(406, concat("number overflow parsing '", number_string, '\''), nullptr));
|
||||||
}
|
}
|
||||||
return sax->number_float(parsed_float, std::move(number_string));
|
// number_string is a std::string, while the SAX interface takes a
|
||||||
|
// string_t; convert explicitly, as the two are only implicitly
|
||||||
|
// convertible for some string types
|
||||||
|
return sax->number_float(parsed_float, string_t(number_string.data(), number_string.size()));
|
||||||
}
|
}
|
||||||
case token_type::uninitialized:
|
case token_type::uninitialized:
|
||||||
case token_type::literal_true:
|
case token_type::literal_true:
|
||||||
|
|||||||
@@ -8,11 +8,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm> // find_if
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <string> // string
|
#include <string> // string
|
||||||
#include <type_traits> // enable_if_t
|
#include <type_traits> // enable_if_t
|
||||||
#include <utility> // move, pair
|
#include <utility> // move
|
||||||
#include <vector> // vector
|
#include <vector> // vector
|
||||||
|
|
||||||
#include <nlohmann/detail/exceptions.hpp>
|
#include <nlohmann/detail/exceptions.hpp>
|
||||||
@@ -250,7 +249,7 @@ class json_sax_dom_parser
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
||||||
{
|
{
|
||||||
return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -299,7 +298,7 @@ class json_sax_dom_parser
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
||||||
{
|
{
|
||||||
return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -569,7 +568,7 @@ class json_sax_dom_callback_parser
|
|||||||
// check object limit
|
// check object limit
|
||||||
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
||||||
{
|
{
|
||||||
return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -586,17 +585,7 @@ class json_sax_dom_callback_parser
|
|||||||
// add discarded value at the given key and store the reference for later
|
// add discarded value at the given key and store the reference for later
|
||||||
if (keep && ref_stack.back())
|
if (keep && ref_stack.back())
|
||||||
{
|
{
|
||||||
auto& obj = *ref_stack.back()->m_data.m_value.object;
|
object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded);
|
||||||
const auto it = obj.find(val);
|
|
||||||
if (it != obj.end())
|
|
||||||
{
|
|
||||||
// this is a duplicate key (legal in JSON); remember its
|
|
||||||
// current value so it can be restored later if the new
|
|
||||||
// value is rejected by the callback, instead of being
|
|
||||||
// erased together with the discarded placeholder
|
|
||||||
duplicate_key_stash.emplace_back(&(it->second), it->second);
|
|
||||||
}
|
|
||||||
object_element = &(obj[val] = discarded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -608,18 +597,13 @@ class json_sax_dom_callback_parser
|
|||||||
{
|
{
|
||||||
if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
|
if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
|
||||||
{
|
{
|
||||||
// discard object, unless this slot holds a duplicate key's
|
// discard object
|
||||||
// previous value pending restoration, in which case that
|
*ref_stack.back() = discarded;
|
||||||
// value is restored instead of being discarded
|
|
||||||
if (!resolve_duplicate_key_stash(ref_stack.back(), true))
|
|
||||||
{
|
|
||||||
*ref_stack.back() = discarded;
|
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Set start/end positions for discarded object.
|
// Set start/end positions for discarded object.
|
||||||
handle_diagnostic_positions_for_json_value(*ref_stack.back());
|
handle_diagnostic_positions_for_json_value(*ref_stack.back());
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -633,10 +617,6 @@ class json_sax_dom_callback_parser
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
// this object is finally, definitively kept; drop any
|
|
||||||
// pending duplicate-key stash entry for its slot since it
|
|
||||||
// can no longer be restored
|
|
||||||
resolve_duplicate_key_stash(ref_stack.back(), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,7 +659,7 @@ class json_sax_dom_callback_parser
|
|||||||
// check array limit
|
// check array limit
|
||||||
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
||||||
{
|
{
|
||||||
return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,25 +686,16 @@ class json_sax_dom_callback_parser
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
// this array is finally, definitively kept; drop any
|
|
||||||
// pending duplicate-key stash entry for its slot since it
|
|
||||||
// can no longer be restored
|
|
||||||
resolve_duplicate_key_stash(ref_stack.back(), false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// discard array, unless this slot holds a duplicate key's
|
// discard array
|
||||||
// previous value pending restoration, in which case that
|
*ref_stack.back() = discarded;
|
||||||
// value is restored instead of being discarded
|
|
||||||
if (!resolve_duplicate_key_stash(ref_stack.back(), true))
|
|
||||||
{
|
|
||||||
*ref_stack.back() = discarded;
|
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Set start/end positions for discarded array.
|
// Set start/end positions for discarded array.
|
||||||
handle_diagnostic_positions_for_json_value(*ref_stack.back());
|
handle_diagnostic_positions_for_json_value(*ref_stack.back());
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -838,48 +809,14 @@ class json_sax_dom_callback_parser
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// if there is a pending duplicate-key stash entry for this exact slot,
|
/// remove the discarded value the callback rejected from its parent
|
||||||
/// remove it from the stash; if restore_value is true, the stashed
|
static void remove_discarded_value(BasicJsonType& parent)
|
||||||
/// previous value is moved back into the slot first (use this when the
|
|
||||||
/// new value at that slot was rejected); otherwise the stash entry is
|
|
||||||
/// simply dropped (use this when the new value was accepted, so it
|
|
||||||
/// correctly supersedes the old one and no restore should ever happen
|
|
||||||
/// for this slot again)
|
|
||||||
/// @return whether a matching stash entry was found (and processed)
|
|
||||||
bool resolve_duplicate_key_stash(BasicJsonType* slot, bool restore_value)
|
|
||||||
{
|
|
||||||
const auto it = std::find_if(duplicate_key_stash.begin(), duplicate_key_stash.end(),
|
|
||||||
[slot](const std::pair<BasicJsonType*, BasicJsonType>& entry)
|
|
||||||
{
|
|
||||||
return entry.first == slot;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (it == duplicate_key_stash.end())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restore_value)
|
|
||||||
{
|
|
||||||
*slot = std::move(it->second);
|
|
||||||
}
|
|
||||||
duplicate_key_stash.erase(it);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// remove the discarded value the callback rejected from its parent,
|
|
||||||
/// unless it is a duplicate key's slot with a stashed previous value,
|
|
||||||
/// in which case that previous value is restored instead
|
|
||||||
void remove_discarded_value(BasicJsonType& parent)
|
|
||||||
{
|
{
|
||||||
for (auto it = parent.begin(); it != parent.end(); ++it)
|
for (auto it = parent.begin(); it != parent.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->is_discarded())
|
if (it->is_discarded())
|
||||||
{
|
{
|
||||||
if (!resolve_duplicate_key_stash(&(*it), true))
|
parent.erase(it);
|
||||||
{
|
|
||||||
parent.erase(it);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -977,16 +914,6 @@ class json_sax_dom_callback_parser
|
|||||||
|
|
||||||
JSON_ASSERT(object_element);
|
JSON_ASSERT(object_element);
|
||||||
*object_element = std::move(value);
|
*object_element = std::move(value);
|
||||||
if (!skip_callback)
|
|
||||||
{
|
|
||||||
// this scalar value finally, definitively replaces whatever was
|
|
||||||
// at this slot; drop any pending duplicate-key stash entry for
|
|
||||||
// it since it can no longer be restored (a container value at
|
|
||||||
// this slot is resolved later, in end_object()/end_array(),
|
|
||||||
// since skip_callback is true for the placeholder handling that
|
|
||||||
// happens here for those)
|
|
||||||
resolve_duplicate_key_stash(object_element, false);
|
|
||||||
}
|
|
||||||
return {true, object_element};
|
return {true, object_element};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1000,12 +927,6 @@ class json_sax_dom_callback_parser
|
|||||||
std::vector<bool> key_keep_stack {}; // NOLINT(readability-redundant-member-init)
|
std::vector<bool> key_keep_stack {}; // NOLINT(readability-redundant-member-init)
|
||||||
/// helper to hold the reference for the next object element
|
/// helper to hold the reference for the next object element
|
||||||
BasicJsonType* object_element = nullptr;
|
BasicJsonType* object_element = nullptr;
|
||||||
/// stash of (slot pointer, previous value) for object members that
|
|
||||||
/// already existed when key() was called again for the same key
|
|
||||||
/// (duplicate keys); used to restore the previous value if the new
|
|
||||||
/// value is later rejected by the callback, instead of erasing the
|
|
||||||
/// member entirely
|
|
||||||
std::vector<std::pair<BasicJsonType*, BasicJsonType>> duplicate_key_stash {};
|
|
||||||
/// whether a syntax error occurred
|
/// whether a syntax error occurred
|
||||||
bool errored = false;
|
bool errored = false;
|
||||||
/// callback function
|
/// callback function
|
||||||
|
|||||||
@@ -88,8 +88,13 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
|
|
||||||
iter_impl() = default;
|
iter_impl() = default;
|
||||||
~iter_impl() = default;
|
~iter_impl() = default;
|
||||||
iter_impl(iter_impl&&) noexcept = default;
|
// the exception specification is left to be computed rather than declared:
|
||||||
iter_impl& operator=(iter_impl&&) noexcept = default;
|
// an array or object type whose iterator is not nothrow move constructible
|
||||||
|
// (std::deque's is not before libstdc++ 11) would make a declared noexcept
|
||||||
|
// differ from the implicit one, which deletes the function -- and is an
|
||||||
|
// error outright with older compilers
|
||||||
|
iter_impl(iter_impl&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
|
||||||
|
iter_impl& operator=(iter_impl&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief constructor for a given JSON instance
|
@brief constructor for a given JSON instance
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#endif // JSON_NO_IO
|
#endif // JSON_NO_IO
|
||||||
#include <limits> // max
|
#include <limits> // max
|
||||||
#include <numeric> // accumulate
|
#include <numeric> // accumulate
|
||||||
|
#include <set> // set
|
||||||
#include <string> // string
|
#include <string> // string
|
||||||
#include <utility> // move
|
#include <utility> // move
|
||||||
#include <vector> // vector
|
#include <vector> // vector
|
||||||
@@ -71,7 +72,7 @@ class json_pointer
|
|||||||
string_t{},
|
string_t{},
|
||||||
[](const string_t& a, const string_t& b)
|
[](const string_t& a, const string_t& b)
|
||||||
{
|
{
|
||||||
return detail::concat(a, '/', detail::escape(b));
|
return detail::concat<string_t>(a, '/', detail::escape(b));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +266,7 @@ class json_pointer
|
|||||||
JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
|
JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* p = s.c_str();
|
const char* p = s.data();
|
||||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||||
errno = 0; // strtoull doesn't reset errno
|
errno = 0; // strtoull doesn't reset errno
|
||||||
const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
|
const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
|
||||||
@@ -300,19 +301,35 @@ class json_pointer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/*!
|
||||||
|
@brief the reference token sequences that denote arrays
|
||||||
|
|
||||||
|
@ref unflatten collects the pointer prefixes that have a reference token 0
|
||||||
|
among their children; @ref get_and_create creates arrays exactly below
|
||||||
|
those prefixes and objects everywhere else. Deciding this up front keeps
|
||||||
|
the result independent of the order in which the flattened object is
|
||||||
|
iterated, which is unspecified for some object types.
|
||||||
|
*/
|
||||||
|
using array_parents_t = std::set<std::vector<string_t>>;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief create and return a reference to the pointed to value
|
@brief create and return a reference to the pointed to value
|
||||||
|
|
||||||
@complexity Linear in the number of reference tokens.
|
@complexity Linear in the number of reference tokens.
|
||||||
|
|
||||||
|
@throw parse_error.106 if an array index begins with '0'
|
||||||
@throw parse_error.109 if array index is not a number
|
@throw parse_error.109 if array index is not a number
|
||||||
@throw type_error.313 if value cannot be unflattened
|
@throw type_error.313 if value cannot be unflattened
|
||||||
*/
|
*/
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
BasicJsonType& get_and_create(BasicJsonType& j) const
|
BasicJsonType& get_and_create(BasicJsonType& j, const array_parents_t& array_parents) const
|
||||||
{
|
{
|
||||||
auto* result = &j;
|
auto* result = &j;
|
||||||
|
|
||||||
|
// the reference tokens that have been consumed so far; used to look up
|
||||||
|
// whether the value to be created below is an array or an object
|
||||||
|
std::vector<string_t> prefix;
|
||||||
|
|
||||||
// in case no reference tokens exist, return a reference to the JSON value
|
// in case no reference tokens exist, return a reference to the JSON value
|
||||||
// j which will be overwritten by a primitive value
|
// j which will be overwritten by a primitive value
|
||||||
for (const auto& reference_token : reference_tokens)
|
for (const auto& reference_token : reference_tokens)
|
||||||
@@ -321,10 +338,11 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
case detail::value_t::null:
|
case detail::value_t::null:
|
||||||
{
|
{
|
||||||
if (reference_token == "0")
|
if (array_parents.find(prefix) != array_parents.end())
|
||||||
{
|
{
|
||||||
// start a new array if the reference token is 0
|
// some reference token below this position is 0, so the
|
||||||
result = &result->operator[](0);
|
// value is an array
|
||||||
|
result = &result->operator[](array_index<BasicJsonType>(reference_token));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -364,6 +382,8 @@ class json_pointer
|
|||||||
default:
|
default:
|
||||||
JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
|
JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prefix.push_back(reference_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *result;
|
return *result;
|
||||||
@@ -823,7 +843,8 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
// use the text between the beginning of the reference token
|
// use the text between the beginning of the reference token
|
||||||
// (start) and the last slash (slash).
|
// (start) and the last slash (slash).
|
||||||
auto reference_token = reference_string.substr(start, slash - start);
|
const auto count = (slash == string_t::npos ? reference_string.size() : slash) - start;
|
||||||
|
auto reference_token = string_t(reference_string.data() + start, count);
|
||||||
|
|
||||||
// check reference tokens are properly escaped
|
// check reference tokens are properly escaped
|
||||||
for (std::size_t pos = reference_token.find_first_of('~');
|
for (std::size_t pos = reference_token.find_first_of('~');
|
||||||
@@ -939,6 +960,24 @@ class json_pointer
|
|||||||
|
|
||||||
BasicJsonType result;
|
BasicJsonType result;
|
||||||
|
|
||||||
|
// collect the pointer prefixes that have a reference token 0 among
|
||||||
|
// their children; the values below them are arrays, all others are
|
||||||
|
// objects (see array_parents_t)
|
||||||
|
array_parents_t array_parents;
|
||||||
|
for (const auto& element : *value.m_data.m_value.object)
|
||||||
|
{
|
||||||
|
json_pointer ptr(element.first);
|
||||||
|
std::vector<string_t> prefix;
|
||||||
|
for (auto& reference_token : ptr.reference_tokens)
|
||||||
|
{
|
||||||
|
if (reference_token == "0")
|
||||||
|
{
|
||||||
|
array_parents.insert(prefix);
|
||||||
|
}
|
||||||
|
prefix.push_back(std::move(reference_token));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// iterate the JSON object values
|
// iterate the JSON object values
|
||||||
for (const auto& element : *value.m_data.m_value.object)
|
for (const auto& element : *value.m_data.m_value.object)
|
||||||
{
|
{
|
||||||
@@ -951,7 +990,7 @@ class json_pointer
|
|||||||
// that if the JSON pointer is "" (i.e., points to the whole value),
|
// that if the JSON pointer is "" (i.e., points to the whole value),
|
||||||
// function get_and_create returns a reference to the result itself.
|
// function get_and_create returns a reference to the result itself.
|
||||||
// An assignment will then create a primitive value.
|
// An assignment will then create a primitive value.
|
||||||
json_pointer(element.first).get_and_create(result) = element.second;
|
json_pointer(element.first).get_and_create(result, array_parents) = element.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -172,17 +172,18 @@ struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using detect_key_compare = typename T::key_compare;
|
using detect_key_compare = typename T::key_compare;
|
||||||
|
|
||||||
template<typename T>
|
// obtains the actual object key comparator: object_t::key_compare if the
|
||||||
struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};
|
// object type defines it, and default_object_comparator_t otherwise
|
||||||
|
//
|
||||||
// obtains the actual object key comparator
|
// note detected_or_t is used rather than std::conditional, because the latter
|
||||||
|
// names both of its type arguments eagerly; object_t::key_compare would then
|
||||||
|
// be a hard error for an object type that does not define it
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
struct actual_object_comparator
|
struct actual_object_comparator
|
||||||
{
|
{
|
||||||
using object_t = typename BasicJsonType::object_t;
|
using object_t = typename BasicJsonType::object_t;
|
||||||
using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
|
using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
|
||||||
using type = typename std::conditional < has_key_compare<object_t>::value,
|
using type = detected_or_t<object_comparator_t, detect_key_compare, object_t>;
|
||||||
typename object_t::key_compare, object_comparator_t>::type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
@@ -778,6 +779,22 @@ using has_erase_with_key_type = typename std::conditional <
|
|||||||
std::true_type,
|
std::true_type,
|
||||||
std::false_type >::type;
|
std::false_type >::type;
|
||||||
|
|
||||||
|
template<typename ObjectType, typename IteratorType>
|
||||||
|
using detect_erase_with_iterator = decltype(std::declval<ObjectType&>().erase(std::declval<IteratorType>()));
|
||||||
|
|
||||||
|
// type trait to check if erase(iterator) returns void instead of the following
|
||||||
|
// iterator, as the object types that do not compute a successor the caller may
|
||||||
|
// not need do
|
||||||
|
template<typename ObjectType, typename IteratorType>
|
||||||
|
using erase_returns_void = is_detected_exact<void, detect_erase_with_iterator, ObjectType, IteratorType>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using detect_capacity = decltype(std::declval<const T&>().capacity());
|
||||||
|
|
||||||
|
// type trait to check if a type has a capacity() member function
|
||||||
|
template<typename T>
|
||||||
|
struct has_capacity : std::integral_constant<bool, is_detected<detect_capacity, T>::value> {};
|
||||||
|
|
||||||
// a naive helper to check if a type is an ordered_map (exploits the fact that
|
// a naive helper to check if a type is an ordered_map (exploits the fact that
|
||||||
// ordered_map inherits capacity() from std::vector)
|
// ordered_map inherits capacity() from std::vector)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ class binary_writer
|
|||||||
|
|
||||||
// step 2: write the string
|
// step 2: write the string
|
||||||
oa->write_characters(
|
oa->write_characters(
|
||||||
reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
|
reinterpret_cast<const CharType*>(j.m_data.m_value.string->data()),
|
||||||
j.m_data.m_value.string->size());
|
j.m_data.m_value.string->size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -581,7 +581,7 @@ class binary_writer
|
|||||||
|
|
||||||
// step 2: write the string
|
// step 2: write the string
|
||||||
oa->write_characters(
|
oa->write_characters(
|
||||||
reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
|
reinterpret_cast<const CharType*>(j.m_data.m_value.string->data()),
|
||||||
j.m_data.m_value.string->size());
|
j.m_data.m_value.string->size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -798,7 +798,7 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata);
|
write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata);
|
||||||
oa->write_characters(
|
oa->write_characters(
|
||||||
reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
|
reinterpret_cast<const CharType*>(j.m_data.m_value.string->data()),
|
||||||
j.m_data.m_value.string->size());
|
j.m_data.m_value.string->size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -887,7 +887,9 @@ class binary_writer
|
|||||||
for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i)
|
for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i)
|
||||||
{
|
{
|
||||||
oa->write_character(to_char_type(bjdata_draft3 ? 'B' : 'U'));
|
oa->write_character(to_char_type(bjdata_draft3 ? 'B' : 'U'));
|
||||||
oa->write_character(to_char_type(j.m_data.m_value.binary->data()[i]));
|
// the cast is needed for binary types whose value type
|
||||||
|
// is not an integer (e.g., std::byte)
|
||||||
|
oa->write_character(to_char_type(static_cast<std::uint8_t>(j.m_data.m_value.binary->data()[i])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -948,7 +950,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);
|
write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);
|
||||||
oa->write_characters(
|
oa->write_characters(
|
||||||
reinterpret_cast<const CharType*>(el.first.c_str()),
|
reinterpret_cast<const CharType*>(el.first.data()),
|
||||||
el.first.size());
|
el.first.size());
|
||||||
write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version);
|
write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version);
|
||||||
}
|
}
|
||||||
@@ -1011,8 +1013,11 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
oa->write_character(to_char_type(element_type));
|
oa->write_character(to_char_type(element_type));
|
||||||
oa->write_characters(
|
oa->write_characters(
|
||||||
reinterpret_cast<const CharType*>(name.c_str()),
|
reinterpret_cast<const CharType*>(name.data()),
|
||||||
name.size() + 1u);
|
name.size());
|
||||||
|
// the terminating null byte is written explicitly rather than taken
|
||||||
|
// from the buffer, so that string_t::data() need not be null-terminated
|
||||||
|
oa->write_character(to_char_type(0x00));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1053,8 +1058,11 @@ class binary_writer
|
|||||||
|
|
||||||
write_number<std::int32_t>(to_bson_length(value.size() + 1ul), true);
|
write_number<std::int32_t>(to_bson_length(value.size() + 1ul), true);
|
||||||
oa->write_characters(
|
oa->write_characters(
|
||||||
reinterpret_cast<const CharType*>(value.c_str()),
|
reinterpret_cast<const CharType*>(value.data()),
|
||||||
value.size() + 1);
|
value.size());
|
||||||
|
// the terminating null byte is written explicitly rather than taken
|
||||||
|
// from the buffer, so that string_t::data() need not be null-terminated
|
||||||
|
oa->write_character(to_char_type(0x00));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1145,7 +1153,11 @@ class binary_writer
|
|||||||
|
|
||||||
const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)
|
const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)
|
||||||
{
|
{
|
||||||
return result + calc_bson_element_size(std::to_string(array_index++), el);
|
// the index is built as a std::string, while calc_bson_element_size
|
||||||
|
// takes a string_t; convert explicitly, as the two are only
|
||||||
|
// implicitly convertible for some string types
|
||||||
|
const auto key = std::to_string(array_index++);
|
||||||
|
return result + calc_bson_element_size(string_t(key.data(), key.size()), el);
|
||||||
});
|
});
|
||||||
|
|
||||||
return sizeof(std::int32_t) + embedded_document_size + 1ul;
|
return sizeof(std::int32_t) + embedded_document_size + 1ul;
|
||||||
@@ -1172,7 +1184,11 @@ class binary_writer
|
|||||||
|
|
||||||
for (const auto& el : value)
|
for (const auto& el : value)
|
||||||
{
|
{
|
||||||
write_bson_element(std::to_string(array_index++), el);
|
// the index is built as a std::string, while write_bson_element takes
|
||||||
|
// a string_t; convert explicitly, as the two are only implicitly
|
||||||
|
// convertible for some string types
|
||||||
|
const auto key = std::to_string(array_index++);
|
||||||
|
write_bson_element(string_t(key.data(), key.size()), el);
|
||||||
}
|
}
|
||||||
|
|
||||||
oa->write_character(to_char_type(0x00));
|
oa->write_character(to_char_type(0x00));
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ class serializer
|
|||||||
auto i = val.m_data.m_value.object->cbegin();
|
auto i = val.m_data.m_value.object->cbegin();
|
||||||
for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
|
for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
|
||||||
{
|
{
|
||||||
o->write_characters(indent_string.c_str(), new_indent);
|
o->write_characters(indent_string.data(), new_indent);
|
||||||
o->write_character('\"');
|
o->write_character('\"');
|
||||||
dump_escaped(i->first, ensure_ascii);
|
dump_escaped(i->first, ensure_ascii);
|
||||||
o->write_characters("\": ", 3);
|
o->write_characters("\": ", 3);
|
||||||
@@ -146,14 +146,14 @@ class serializer
|
|||||||
// last element
|
// last element
|
||||||
JSON_ASSERT(i != val.m_data.m_value.object->cend());
|
JSON_ASSERT(i != val.m_data.m_value.object->cend());
|
||||||
JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
|
JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
|
||||||
o->write_characters(indent_string.c_str(), new_indent);
|
o->write_characters(indent_string.data(), new_indent);
|
||||||
o->write_character('\"');
|
o->write_character('\"');
|
||||||
dump_escaped(i->first, ensure_ascii);
|
dump_escaped(i->first, ensure_ascii);
|
||||||
o->write_characters("\": ", 3);
|
o->write_characters("\": ", 3);
|
||||||
dump(i->second, true, ensure_ascii, indent_step, new_indent);
|
dump(i->second, true, ensure_ascii, indent_step, new_indent);
|
||||||
|
|
||||||
o->write_character('\n');
|
o->write_character('\n');
|
||||||
o->write_characters(indent_string.c_str(), current_indent);
|
o->write_characters(indent_string.data(), current_indent);
|
||||||
o->write_character('}');
|
o->write_character('}');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -208,18 +208,18 @@ class serializer
|
|||||||
for (auto i = val.m_data.m_value.array->cbegin();
|
for (auto i = val.m_data.m_value.array->cbegin();
|
||||||
i != val.m_data.m_value.array->cend() - 1; ++i)
|
i != val.m_data.m_value.array->cend() - 1; ++i)
|
||||||
{
|
{
|
||||||
o->write_characters(indent_string.c_str(), new_indent);
|
o->write_characters(indent_string.data(), new_indent);
|
||||||
dump(*i, true, ensure_ascii, indent_step, new_indent);
|
dump(*i, true, ensure_ascii, indent_step, new_indent);
|
||||||
o->write_characters(",\n", 2);
|
o->write_characters(",\n", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// last element
|
// last element
|
||||||
JSON_ASSERT(!val.m_data.m_value.array->empty());
|
JSON_ASSERT(!val.m_data.m_value.array->empty());
|
||||||
o->write_characters(indent_string.c_str(), new_indent);
|
o->write_characters(indent_string.data(), new_indent);
|
||||||
dump(val.m_data.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
|
dump(val.m_data.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
|
||||||
|
|
||||||
o->write_character('\n');
|
o->write_character('\n');
|
||||||
o->write_characters(indent_string.c_str(), current_indent);
|
o->write_characters(indent_string.data(), current_indent);
|
||||||
o->write_character(']');
|
o->write_character(']');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -265,7 +265,7 @@ class serializer
|
|||||||
indent_string.resize(indent_string.size() * 2, ' ');
|
indent_string.resize(indent_string.size() * 2, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
o->write_characters(indent_string.c_str(), new_indent);
|
o->write_characters(indent_string.data(), new_indent);
|
||||||
|
|
||||||
o->write_characters("\"bytes\": [", 10);
|
o->write_characters("\"bytes\": [", 10);
|
||||||
|
|
||||||
@@ -274,14 +274,14 @@ class serializer
|
|||||||
for (auto i = val.m_data.m_value.binary->cbegin();
|
for (auto i = val.m_data.m_value.binary->cbegin();
|
||||||
i != val.m_data.m_value.binary->cend() - 1; ++i)
|
i != val.m_data.m_value.binary->cend() - 1; ++i)
|
||||||
{
|
{
|
||||||
dump_integer(*i);
|
dump_integer(to_byte_value(*i));
|
||||||
o->write_characters(", ", 2);
|
o->write_characters(", ", 2);
|
||||||
}
|
}
|
||||||
dump_integer(val.m_data.m_value.binary->back());
|
dump_integer(to_byte_value(val.m_data.m_value.binary->back()));
|
||||||
}
|
}
|
||||||
|
|
||||||
o->write_characters("],\n", 3);
|
o->write_characters("],\n", 3);
|
||||||
o->write_characters(indent_string.c_str(), new_indent);
|
o->write_characters(indent_string.data(), new_indent);
|
||||||
|
|
||||||
o->write_characters("\"subtype\": ", 11);
|
o->write_characters("\"subtype\": ", 11);
|
||||||
if (val.m_data.m_value.binary->has_subtype())
|
if (val.m_data.m_value.binary->has_subtype())
|
||||||
@@ -293,7 +293,7 @@ class serializer
|
|||||||
o->write_characters("null", 4);
|
o->write_characters("null", 4);
|
||||||
}
|
}
|
||||||
o->write_character('\n');
|
o->write_character('\n');
|
||||||
o->write_characters(indent_string.c_str(), current_indent);
|
o->write_characters(indent_string.data(), current_indent);
|
||||||
o->write_character('}');
|
o->write_character('}');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -305,10 +305,10 @@ class serializer
|
|||||||
for (auto i = val.m_data.m_value.binary->cbegin();
|
for (auto i = val.m_data.m_value.binary->cbegin();
|
||||||
i != val.m_data.m_value.binary->cend() - 1; ++i)
|
i != val.m_data.m_value.binary->cend() - 1; ++i)
|
||||||
{
|
{
|
||||||
dump_integer(*i);
|
dump_integer(to_byte_value(*i));
|
||||||
o->write_character(',');
|
o->write_character(',');
|
||||||
}
|
}
|
||||||
dump_integer(val.m_data.m_value.binary->back());
|
dump_integer(to_byte_value(val.m_data.m_value.binary->back()));
|
||||||
}
|
}
|
||||||
|
|
||||||
o->write_characters("],\"subtype\":", 12);
|
o->write_characters("],\"subtype\":", 12);
|
||||||
@@ -596,7 +596,7 @@ class serializer
|
|||||||
{
|
{
|
||||||
case error_handler_t::strict:
|
case error_handler_t::strict:
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr));
|
JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s[s.size() - 1] | 0))), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
case error_handler_t::ignore:
|
case error_handler_t::ignore:
|
||||||
@@ -703,6 +703,19 @@ class serializer
|
|||||||
pos += 6;
|
pos += 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief convert a single element of a binary value to its byte value
|
||||||
|
|
||||||
|
The elements of a binary value are dumped as the numbers 0..255, regardless
|
||||||
|
of the value type of the configured BinaryType: that type may be signed
|
||||||
|
(`char`), unsigned (`std::uint8_t`), or not an integer at all
|
||||||
|
(`std::byte`), none of which @ref dump_integer can handle uniformly.
|
||||||
|
*/
|
||||||
|
static std::uint8_t to_byte_value(binary_char_t x) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::uint8_t>(x);
|
||||||
|
}
|
||||||
|
|
||||||
// templates to avoid warnings about useless casts
|
// templates to avoid warnings about useless casts
|
||||||
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
|
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
|
||||||
bool is_negative_number(NumberType x)
|
bool is_negative_number(NumberType x)
|
||||||
@@ -728,8 +741,7 @@ class serializer
|
|||||||
template < typename NumberType, detail::enable_if_t <
|
template < typename NumberType, detail::enable_if_t <
|
||||||
std::is_integral<NumberType>::value ||
|
std::is_integral<NumberType>::value ||
|
||||||
std::is_same<NumberType, number_unsigned_t>::value ||
|
std::is_same<NumberType, number_unsigned_t>::value ||
|
||||||
std::is_same<NumberType, number_integer_t>::value ||
|
std::is_same<NumberType, number_integer_t>::value,
|
||||||
std::is_same<NumberType, binary_char_t>::value,
|
|
||||||
int > = 0 >
|
int > = 0 >
|
||||||
void dump_integer(NumberType x)
|
void dump_integer(NumberType x)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,50 +8,56 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
|
||||||
#include <nlohmann/detail/abi_macros.hpp>
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief replace all occurrences of a substring by another string
|
|
||||||
|
|
||||||
@param[in,out] s the string to manipulate; changed so that all
|
|
||||||
occurrences of @a f are replaced with @a t
|
|
||||||
@param[in] f the substring to replace with @a t
|
|
||||||
@param[in] t the string to replace @a f
|
|
||||||
|
|
||||||
@pre The search string @a f must not be empty. **This precondition is
|
|
||||||
enforced with an assertion.**
|
|
||||||
|
|
||||||
@since version 2.0.0
|
|
||||||
*/
|
|
||||||
template<typename StringType>
|
|
||||||
inline void replace_substring(StringType& s, const StringType& f,
|
|
||||||
const StringType& t)
|
|
||||||
{
|
|
||||||
JSON_ASSERT(!f.empty());
|
|
||||||
for (auto pos = s.find(f); // find the first occurrence of f
|
|
||||||
pos != StringType::npos; // make sure f was found
|
|
||||||
s.replace(pos, f.size(), t), // replace with t, and
|
|
||||||
pos = s.find(f, pos + t.size())) // find the next occurrence of f
|
|
||||||
{}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief string escaping as described in RFC 6901 (Sect. 4)
|
* @brief string escaping as described in RFC 6901 (Sect. 4)
|
||||||
* @param[in] s string to escape
|
* @param[in] s string to escape
|
||||||
* @return escaped string
|
* @return escaped string
|
||||||
*
|
*
|
||||||
* Note the order of escaping "~" to "~0" and "/" to "~1" is important.
|
* Note the order of escaping "~" to "~0" and "/" to "~1" is important.
|
||||||
|
*
|
||||||
|
* The string is rebuilt in a single pass, appending whole runs between the
|
||||||
|
* characters that need escaping. Scanning with find_first_of() keeps the
|
||||||
|
* common case -- nothing to escape -- as fast as a single search, while
|
||||||
|
* repeated replace() calls would move the tail of the string once per
|
||||||
|
* escaped character.
|
||||||
*/
|
*/
|
||||||
template<typename StringType>
|
template<typename StringType>
|
||||||
inline StringType escape(StringType s)
|
inline StringType escape(const StringType& s)
|
||||||
{
|
{
|
||||||
replace_substring(s, StringType{"~"}, StringType{"~0"});
|
auto next_special = [&s](std::size_t from)
|
||||||
replace_substring(s, StringType{"/"}, StringType{"~1"});
|
{
|
||||||
return s;
|
const auto tilde = s.find_first_of('~', from);
|
||||||
|
const auto slash = s.find_first_of('/', from);
|
||||||
|
return tilde < slash ? tilde : slash; // npos is the largest value
|
||||||
|
};
|
||||||
|
|
||||||
|
auto pos = next_special(0);
|
||||||
|
if (pos == StringType::npos)
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringType result;
|
||||||
|
result.reserve(s.size() + 2);
|
||||||
|
|
||||||
|
std::size_t run = 0;
|
||||||
|
while (pos != StringType::npos)
|
||||||
|
{
|
||||||
|
result.append(s.data() + run, pos - run);
|
||||||
|
result.append(s[pos] == '~' ? "~0" : "~1", 2);
|
||||||
|
run = pos + 1;
|
||||||
|
pos = next_special(run);
|
||||||
|
}
|
||||||
|
result.append(s.data() + run, s.size() - run);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -60,12 +66,43 @@ inline StringType escape(StringType s)
|
|||||||
* @return unescaped string
|
* @return unescaped string
|
||||||
*
|
*
|
||||||
* Note the order of escaping "~1" to "/" and "~0" to "~" is important.
|
* Note the order of escaping "~1" to "/" and "~0" to "~" is important.
|
||||||
|
*
|
||||||
|
* Rebuilt in a single pass, see @ref escape. A "~" that is followed by
|
||||||
|
* neither "0" nor "1" is passed through unchanged; @ref json_pointer rejects
|
||||||
|
* such input before it gets here.
|
||||||
*/
|
*/
|
||||||
template<typename StringType>
|
template<typename StringType>
|
||||||
inline void unescape(StringType& s)
|
inline void unescape(StringType& s)
|
||||||
{
|
{
|
||||||
replace_substring(s, StringType{"~1"}, StringType{"/"});
|
auto pos = s.find_first_of('~', 0);
|
||||||
replace_substring(s, StringType{"~0"}, StringType{"~"});
|
if (pos == StringType::npos)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringType result;
|
||||||
|
result.reserve(s.size());
|
||||||
|
|
||||||
|
std::size_t run = 0;
|
||||||
|
while (pos != StringType::npos)
|
||||||
|
{
|
||||||
|
result.append(s.data() + run, pos - run);
|
||||||
|
|
||||||
|
const auto next = pos + 1;
|
||||||
|
if (next < s.size() && (s[next] == '0' || s[next] == '1'))
|
||||||
|
{
|
||||||
|
result.append(s[next] == '0' ? "~" : "/", 1);
|
||||||
|
run = pos + 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.append("~", 1);
|
||||||
|
run = pos + 1;
|
||||||
|
}
|
||||||
|
pos = s.find_first_of('~', run);
|
||||||
|
}
|
||||||
|
result.append(s.data() + run, s.size() - run);
|
||||||
|
s = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|||||||
@@ -9,12 +9,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <cmath> // isnan, ldexp, trunc
|
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdint> // uint8_t
|
#include <cstdint> // uint8_t
|
||||||
#include <limits> // numeric_limits
|
|
||||||
#include <string> // string
|
#include <string> // string
|
||||||
#include <type_traits> // is_signed
|
|
||||||
|
|
||||||
#include <nlohmann/detail/macro_scope.hpp>
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||||
@@ -117,67 +114,5 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief compare an integer with a floating point number without precision loss
|
|
||||||
|
|
||||||
Widening the integer to the floating point type loses precision beyond the
|
|
||||||
float's mantissa, which makes equality intransitive: both 2^63-2 and 2^63-1
|
|
||||||
round to 2^63, so each compares equal to that float while differing from each
|
|
||||||
other. Ordering built on that is not a strict weak ordering, so sorting such
|
|
||||||
values, or using them as keys in an ordered container, is undefined behavior.
|
|
||||||
|
|
||||||
Returns a value to be compared against zero with the original operator, which
|
|
||||||
reproduces the exact ordering. A NaN operand is returned as is, so comparing it
|
|
||||||
against zero keeps NaN's semantics: false for the relational operators and
|
|
||||||
unordered for `<=>`.
|
|
||||||
*/
|
|
||||||
template<typename IntegerType, typename FloatType>
|
|
||||||
FloatType compare_integer_with_float(const IntegerType i, const FloatType f) noexcept
|
|
||||||
{
|
|
||||||
const auto ordered = [](int c) noexcept
|
|
||||||
{
|
|
||||||
return static_cast<FloatType>(c);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (std::isnan(f))
|
|
||||||
{
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// values of IntegerType lie in [-bound, bound) when signed and in
|
|
||||||
// [0, bound) when unsigned; digits excludes the sign bit, so bound is a
|
|
||||||
// power of two that the float represents exactly
|
|
||||||
const FloatType bound = std::ldexp(static_cast<FloatType>(1), std::numeric_limits<IntegerType>::digits);
|
|
||||||
if (f >= bound)
|
|
||||||
{
|
|
||||||
return ordered(-1);
|
|
||||||
}
|
|
||||||
if (std::is_signed<IntegerType>::value ? (f < -bound) : (f < static_cast<FloatType>(0)))
|
|
||||||
{
|
|
||||||
return ordered(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// f is now within the integer's range, so truncating it is exact
|
|
||||||
const FloatType truncated = std::trunc(f);
|
|
||||||
const auto as_integer = static_cast<IntegerType>(truncated);
|
|
||||||
if (i != as_integer)
|
|
||||||
{
|
|
||||||
return ordered(i < as_integer ? -1 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the integer parts agree, so any fractional part decides
|
|
||||||
const FloatType fraction = f - truncated;
|
|
||||||
if (fraction > static_cast<FloatType>(0))
|
|
||||||
{
|
|
||||||
return ordered(-1);
|
|
||||||
}
|
|
||||||
if (fraction < static_cast<FloatType>(0))
|
|
||||||
{
|
|
||||||
return ordered(1);
|
|
||||||
}
|
|
||||||
return ordered(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|||||||
+130
-169
@@ -403,6 +403,18 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
// Two template parameter requirements that would otherwise be silently
|
||||||
|
// violated: neither produces a diagnostic of its own, and both corrupt
|
||||||
|
// values rather than failing.
|
||||||
|
|
||||||
|
static_assert(sizeof(typename BinaryType::value_type) == 1,
|
||||||
|
"BinaryType::value_type must be exactly one byte wide, "
|
||||||
|
"because the binary readers and writers reinterpret the container's storage as raw bytes");
|
||||||
|
|
||||||
|
static_assert(sizeof(NumberUnsignedType) >= sizeof(NumberIntegerType),
|
||||||
|
"NumberUnsignedType must be at least as wide as NumberIntegerType, "
|
||||||
|
"because it has to hold the absolute value of every NumberIntegerType value");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// helper for exception-safe object creation
|
/// helper for exception-safe object creation
|
||||||
@@ -783,21 +795,76 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
reference set_parent(reference j, std::size_t old_capacity = detail::unknown_size())
|
/// @brief erase an element from the object and return the following one
|
||||||
|
/// Not every map returns an iterator from erase(iterator): some containers
|
||||||
|
/// (e.g., Abseil's hash maps) return void to avoid computing a successor
|
||||||
|
/// the caller may not need. Compute it before erasing for those.
|
||||||
|
template < typename It, detail::enable_if_t <
|
||||||
|
!detail::erase_returns_void<object_t, It>::value, int > = 0 >
|
||||||
|
typename object_t::iterator erase_from_object(It pos)
|
||||||
|
{
|
||||||
|
return m_data.m_value.object->erase(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename It, detail::enable_if_t <
|
||||||
|
detail::erase_returns_void<object_t, It>::value, int > = 0 >
|
||||||
|
typename object_t::iterator erase_from_object(It pos)
|
||||||
|
{
|
||||||
|
auto next = std::next(pos);
|
||||||
|
m_data.m_value.object->erase(pos);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief the capacity of the stored array, or unknown_size()
|
||||||
|
/// Only JSON_DIAGNOSTICS uses the value, to detect a reallocation that
|
||||||
|
/// would invalidate the parent pointers. Array types that do not have a
|
||||||
|
/// capacity() member function report unknown_size(), which is treated as
|
||||||
|
/// "the elements may have moved".
|
||||||
|
#if JSON_DIAGNOSTICS
|
||||||
|
template < typename A = array_t, detail::enable_if_t < detail::has_capacity<A>::value, int > = 0 >
|
||||||
|
std::size_t array_capacity() const noexcept
|
||||||
|
{
|
||||||
|
return m_data.m_value.array->capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename A = array_t, detail::enable_if_t < !detail::has_capacity<A>::value, int > = 0 >
|
||||||
|
std::size_t array_capacity() const noexcept
|
||||||
|
{
|
||||||
|
return detail::unknown_size();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static constexpr std::size_t array_capacity() noexcept
|
||||||
|
{
|
||||||
|
return detail::unknown_size();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @brief set the parent of a value that has just been added to an array
|
||||||
|
/// @param j the added value
|
||||||
|
/// @param old_capacity the value @ref array_capacity() returned before the
|
||||||
|
/// insertion
|
||||||
|
reference set_parent_after_array_insert(reference j, std::size_t old_capacity)
|
||||||
{
|
{
|
||||||
#if JSON_DIAGNOSTICS
|
#if JSON_DIAGNOSTICS
|
||||||
if (old_capacity != detail::unknown_size())
|
// see https://github.com/nlohmann/json/issues/2838
|
||||||
|
JSON_ASSERT(type() == value_t::array);
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(old_capacity == detail::unknown_size()
|
||||||
|
|| array_capacity() != old_capacity))
|
||||||
{
|
{
|
||||||
// see https://github.com/nlohmann/json/issues/2838
|
// the capacity has changed, or the array type does not let us tell:
|
||||||
JSON_ASSERT(type() == value_t::array);
|
// the elements may have moved, so update all parents
|
||||||
if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
|
set_parents();
|
||||||
{
|
return j;
|
||||||
// capacity has changed: update all parents
|
|
||||||
set_parents();
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static_cast<void>(old_capacity);
|
||||||
|
#endif
|
||||||
|
return set_parent(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference set_parent(reference j)
|
||||||
|
{
|
||||||
|
#if JSON_DIAGNOSTICS
|
||||||
// ordered_json uses a vector internally, so pointers could have
|
// ordered_json uses a vector internally, so pointers could have
|
||||||
// been invalidated; see https://github.com/nlohmann/json/issues/2962
|
// been invalidated; see https://github.com/nlohmann/json/issues/2962
|
||||||
#ifdef JSON_HEDLEY_MSVC_VERSION
|
#ifdef JSON_HEDLEY_MSVC_VERSION
|
||||||
@@ -816,7 +883,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
j.m_parent = this;
|
j.m_parent = this;
|
||||||
#else
|
#else
|
||||||
static_cast<void>(j);
|
static_cast<void>(j);
|
||||||
static_cast<void>(old_capacity);
|
|
||||||
#endif
|
#endif
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
@@ -2009,22 +2075,17 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
reference at(size_type idx)
|
reference at(size_type idx)
|
||||||
{
|
{
|
||||||
// at only works for arrays
|
// at only works for arrays
|
||||||
if (JSON_HEDLEY_LIKELY(is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
||||||
{
|
|
||||||
JSON_TRY
|
|
||||||
{
|
|
||||||
return set_parent(m_data.m_value.array->at(idx));
|
|
||||||
}
|
|
||||||
JSON_CATCH (std::out_of_range&)
|
|
||||||
{
|
|
||||||
// create a better exception explanation
|
|
||||||
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
|
|
||||||
} // cppcheck-suppress[missingReturn]
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
|
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(idx >= m_data.m_value.array->size()))
|
||||||
|
{
|
||||||
|
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
return set_parent((*m_data.m_value.array)[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified array element with bounds checking
|
/// @brief access specified array element with bounds checking
|
||||||
@@ -2032,22 +2093,17 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
const_reference at(size_type idx) const
|
const_reference at(size_type idx) const
|
||||||
{
|
{
|
||||||
// at only works for arrays
|
// at only works for arrays
|
||||||
if (JSON_HEDLEY_LIKELY(is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
||||||
{
|
|
||||||
JSON_TRY
|
|
||||||
{
|
|
||||||
return m_data.m_value.array->at(idx);
|
|
||||||
}
|
|
||||||
JSON_CATCH (std::out_of_range&)
|
|
||||||
{
|
|
||||||
// create a better exception explanation
|
|
||||||
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
|
|
||||||
} // cppcheck-suppress[missingReturn]
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
|
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(idx >= m_data.m_value.array->size()))
|
||||||
|
{
|
||||||
|
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*m_data.m_value.array)[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified object element with bounds checking
|
/// @brief access specified object element with bounds checking
|
||||||
@@ -2147,12 +2203,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
#if JSON_DIAGNOSTICS
|
#if JSON_DIAGNOSTICS
|
||||||
// remember array size & capacity before resizing
|
// remember array size & capacity before resizing
|
||||||
const auto old_size = m_data.m_value.array->size();
|
const auto old_size = m_data.m_value.array->size();
|
||||||
const auto old_capacity = m_data.m_value.array->capacity();
|
const auto old_capacity = array_capacity();
|
||||||
#endif
|
#endif
|
||||||
m_data.m_value.array->resize(idx + 1);
|
m_data.m_value.array->resize(idx + 1);
|
||||||
|
|
||||||
#if JSON_DIAGNOSTICS
|
#if JSON_DIAGNOSTICS
|
||||||
if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
|
if (JSON_HEDLEY_UNLIKELY(old_capacity == detail::unknown_size()
|
||||||
|
|| array_capacity() != old_capacity))
|
||||||
{
|
{
|
||||||
// capacity has changed: update all parents
|
// capacity has changed: update all parents
|
||||||
set_parents();
|
set_parents();
|
||||||
@@ -2543,7 +2600,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator);
|
result.m_it.object_iterator = erase_from_object(pos.m_it.object_iterator);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3173,9 +3230,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add the element to the array (move semantics)
|
// add the element to the array (move semantics)
|
||||||
const auto old_capacity = m_data.m_value.array->capacity();
|
const auto old_capacity = array_capacity();
|
||||||
m_data.m_value.array->push_back(std::move(val));
|
m_data.m_value.array->push_back(std::move(val));
|
||||||
set_parent(m_data.m_value.array->back(), old_capacity);
|
set_parent_after_array_insert(m_data.m_value.array->back(), old_capacity);
|
||||||
// if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
|
// if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3206,9 +3263,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add the element to the array
|
// add the element to the array
|
||||||
const auto old_capacity = m_data.m_value.array->capacity();
|
const auto old_capacity = array_capacity();
|
||||||
m_data.m_value.array->push_back(val);
|
m_data.m_value.array->push_back(val);
|
||||||
set_parent(m_data.m_value.array->back(), old_capacity);
|
set_parent_after_array_insert(m_data.m_value.array->back(), old_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief add an object to an array
|
/// @brief add an object to an array
|
||||||
@@ -3294,9 +3351,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add the element to the array (perfect forwarding)
|
// add the element to the array (perfect forwarding)
|
||||||
const auto old_capacity = m_data.m_value.array->capacity();
|
const auto old_capacity = array_capacity();
|
||||||
m_data.m_value.array->emplace_back(std::forward<Args>(args)...);
|
m_data.m_value.array->emplace_back(std::forward<Args>(args)...);
|
||||||
return set_parent(m_data.m_value.array->back(), old_capacity);
|
return set_parent_after_array_insert(m_data.m_value.array->back(), old_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief add an object to an object if key does not exist
|
/// @brief add an object to an object if key does not exist
|
||||||
@@ -3375,7 +3432,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/// @sa https://json.nlohmann.me/api/basic_json/insert/
|
/// @sa https://json.nlohmann.me/api/basic_json/insert/
|
||||||
iterator insert(const_iterator pos, basic_json&& val) // NOLINT(performance-unnecessary-value-param)
|
iterator insert(const_iterator pos, basic_json&& val) // NOLINT(performance-unnecessary-value-param)
|
||||||
{
|
{
|
||||||
return insert(pos, val);
|
return insert(std::move(pos), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief inserts copies of element into array
|
/// @brief inserts copies of element into array
|
||||||
@@ -3573,7 +3630,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
{
|
{
|
||||||
using std::swap;
|
using std::swap;
|
||||||
swap(*(m_data.m_value.array), other);
|
swap(*(m_data.m_value.array), other);
|
||||||
set_parents();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3590,7 +3646,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
{
|
{
|
||||||
using std::swap;
|
using std::swap;
|
||||||
swap(*(m_data.m_value.object), other);
|
swap(*(m_data.m_value.object), other);
|
||||||
set_parents();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3705,19 +3760,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
} \
|
} \
|
||||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \
|
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \
|
||||||
{ \
|
{ \
|
||||||
return (detail::compare_integer_with_float(lhs.m_data.m_value.number_integer, rhs.m_data.m_value.number_float)) op (static_cast<number_float_t>(0)); \
|
return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float; \
|
||||||
} \
|
} \
|
||||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \
|
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \
|
||||||
{ \
|
{ \
|
||||||
return (static_cast<number_float_t>(0)) op (detail::compare_integer_with_float(rhs.m_data.m_value.number_integer, lhs.m_data.m_value.number_float)); \
|
return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer); \
|
||||||
} \
|
} \
|
||||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \
|
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \
|
||||||
{ \
|
{ \
|
||||||
return (detail::compare_integer_with_float(lhs.m_data.m_value.number_unsigned, rhs.m_data.m_value.number_float)) op (static_cast<number_float_t>(0)); \
|
return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float; \
|
||||||
} \
|
} \
|
||||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \
|
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \
|
||||||
{ \
|
{ \
|
||||||
return (static_cast<number_float_t>(0)) op (detail::compare_integer_with_float(rhs.m_data.m_value.number_unsigned, lhs.m_data.m_value.number_float)); \
|
return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned); \
|
||||||
} \
|
} \
|
||||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \
|
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \
|
||||||
{ \
|
{ \
|
||||||
@@ -5130,17 +5185,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// We now reached the end of at least one array
|
// We now reached the end of at least one array
|
||||||
// in a second pass, traverse the remaining elements
|
// in a second pass, traverse the remaining elements
|
||||||
|
|
||||||
// remove my remaining elements, highest index first; appending
|
// remove my remaining elements
|
||||||
// in that order avoids the quadratic reinsertion done before
|
const auto end_index = static_cast<difference_type>(result.size());
|
||||||
for (std::size_t j = source.size(); j > i; --j)
|
while (i < source.size())
|
||||||
{
|
{
|
||||||
result.push_back(object(
|
// add operations in reverse order to avoid invalid
|
||||||
|
// indices
|
||||||
|
result.insert(result.begin() + end_index, object(
|
||||||
{
|
{
|
||||||
{"op", "remove"},
|
{"op", "remove"},
|
||||||
{"path", detail::concat<string_t>(path, '/', detail::to_string<string_t>(j - 1))}
|
{"path", detail::concat<string_t>(path, '/', detail::to_string<string_t>(i))}
|
||||||
}));
|
}));
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
i = source.size();
|
|
||||||
|
|
||||||
// add other remaining elements
|
// add other remaining elements
|
||||||
while (i < target.size())
|
while (i < target.size())
|
||||||
@@ -5159,130 +5216,34 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
// first pass: find keys that were deleted (i.e., in source but
|
// first pass: traverse this object's elements
|
||||||
// not in target), and record the keys common to both, in
|
|
||||||
// source's iteration order -- this is a by-product of the
|
|
||||||
// target.find() call already needed to detect removed keys,
|
|
||||||
// so it adds no extra lookups.
|
|
||||||
std::vector<typename object_t::key_type> common_keys_source_order;
|
|
||||||
for (auto it = source.cbegin(); it != source.cend(); ++it)
|
for (auto it = source.cbegin(); it != source.cend(); ++it)
|
||||||
{
|
{
|
||||||
if (target.find(it.key()) == target.end())
|
// escape the key name to be used in a JSON patch
|
||||||
|
const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));
|
||||||
|
|
||||||
|
if (target.find(it.key()) != target.end())
|
||||||
{
|
{
|
||||||
// found a key that is not in target -> remove it
|
// recursive call to compare object values at key it
|
||||||
const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));
|
auto temp_diff = diff(it.value(), target[it.key()], path_key);
|
||||||
|
result.insert(result.end(), temp_diff.begin(), temp_diff.end());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// found a key that is not in o -> remove it
|
||||||
result.push_back(object(
|
result.push_back(object(
|
||||||
{
|
{
|
||||||
{"op", "remove"}, {"path", path_key}
|
{"op", "remove"}, {"path", path_key}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
common_keys_source_order.push_back(it.key());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// second pass: find keys that were added (i.e., in target but
|
// second pass: traverse other object's elements
|
||||||
// not in source), and record the keys common to both, in
|
|
||||||
// target's iteration order -- again a by-product of the
|
|
||||||
// source.find() call already needed to detect added keys. At
|
|
||||||
// the same time, determine whether every added key comes
|
|
||||||
// after every common key in target's order (a precondition
|
|
||||||
// for the fast path below, which only ever appends new keys
|
|
||||||
// at the very end): for an object_t whose iteration order is
|
|
||||||
// a pure function of the key set (e.g. the default std::map,
|
|
||||||
// which always iterates in sorted key order), the order
|
|
||||||
// check further below is always true and this whole
|
|
||||||
// mechanism is effectively a no-op; it only matters for a
|
|
||||||
// reorderable object_t such as the one backing `ordered_json`.
|
|
||||||
// patch ops for keys that were added (i.e., in target but not
|
|
||||||
// in source); built here so the fast path below can reuse
|
|
||||||
// them without a second source.find() per target key. Only
|
|
||||||
// used by the fast path -- the slow (reordering) path
|
|
||||||
// rebuilds "add" ops for every key itself.
|
|
||||||
std::vector<typename object_t::key_type> common_keys_target_order;
|
|
||||||
basic_json added_ops(value_t::array);
|
|
||||||
bool new_keys_form_suffix = true;
|
|
||||||
bool seen_new_key = false;
|
|
||||||
for (auto it = target.cbegin(); it != target.cend(); ++it)
|
for (auto it = target.cbegin(); it != target.cend(); ++it)
|
||||||
{
|
{
|
||||||
if (source.find(it.key()) == source.end())
|
if (source.find(it.key()) == source.end())
|
||||||
{
|
{
|
||||||
seen_new_key = true;
|
// found a key that is not in this -> add it
|
||||||
const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));
|
|
||||||
added_ops.push_back(
|
|
||||||
{
|
|
||||||
{"op", "add"}, {"path", path_key},
|
|
||||||
{"value", it.value()}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
common_keys_target_order.push_back(it.key());
|
|
||||||
if (seen_new_key)
|
|
||||||
{
|
|
||||||
new_keys_form_suffix = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (common_keys_source_order == common_keys_target_order && new_keys_form_suffix)
|
|
||||||
{
|
|
||||||
// fast path: order of common keys already matches (or the
|
|
||||||
// object_t's iteration order does not depend on
|
|
||||||
// insertion history), so a plain per-key recursive diff
|
|
||||||
// is correct and minimal, as before. common_keys_source_order
|
|
||||||
// is, by construction, the subsequence of source's keys
|
|
||||||
// that are common to both objects, in source's iteration
|
|
||||||
// order -- so it can be walked in lockstep with `source`
|
|
||||||
// using a cheap key comparison instead of another lookup.
|
|
||||||
auto common_it = common_keys_source_order.cbegin();
|
|
||||||
for (auto it = source.cbegin(); it != source.cend() && common_it != common_keys_source_order.cend(); ++it)
|
|
||||||
{
|
|
||||||
if (it.key() == *common_it)
|
|
||||||
{
|
|
||||||
const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));
|
|
||||||
auto temp_diff = diff(it.value(), target[it.key()], path_key);
|
|
||||||
result.insert(result.end(), temp_diff.begin(), temp_diff.end());
|
|
||||||
++common_it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// append the "add" ops for brand-new keys collected above
|
|
||||||
// during the pass over target -- no second source.find()
|
|
||||||
// per target key needed
|
|
||||||
result.insert(result.end(), added_ops.begin(), added_ops.end());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// slow path: the common keys are in a different relative
|
|
||||||
// order in source and target (only possible for a
|
|
||||||
// reorderable object_t like ordered_map). Building a
|
|
||||||
// minimal reordering patch is a nontrivial (LCS-like)
|
|
||||||
// problem; instead, remove every common key and re-add it
|
|
||||||
// (with its final target value) in target's order, which
|
|
||||||
// is enough to guarantee source.patch(diff(source,
|
|
||||||
// target)) == target. basic_json::patch()'s "add"
|
|
||||||
// operation on an object uses operator[], which appends
|
|
||||||
// at the end for a vector-backed insertion-ordered map
|
|
||||||
// when the key does not already exist -- so removing a
|
|
||||||
// key and then adding it moves it to the end, fixing its
|
|
||||||
// position.
|
|
||||||
for (const auto& key : common_keys_source_order)
|
|
||||||
{
|
|
||||||
const auto path_key = detail::concat<string_t>(path, '/', detail::escape(key));
|
|
||||||
result.push_back(object(
|
|
||||||
{
|
|
||||||
{"op", "remove"}, {"path", path_key}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// add every key that is either common (just removed
|
|
||||||
// above) or brand new, in target's iteration order, so
|
|
||||||
// that the final order after applying the patch matches
|
|
||||||
// target exactly
|
|
||||||
for (auto it = target.cbegin(); it != target.cend(); ++it)
|
|
||||||
{
|
|
||||||
const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));
|
const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));
|
||||||
result.push_back(
|
result.push_back(
|
||||||
{
|
{
|
||||||
|
|||||||
+358
-407
File diff suppressed because it is too large
Load Diff
@@ -11,8 +11,10 @@
|
|||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
/* forward declarations */
|
/* forward declarations */
|
||||||
class alt_string;
|
class alt_string;
|
||||||
@@ -22,6 +24,10 @@ void int_to_string(alt_string& target, std::size_t value); // NOLINT(misc-use-in
|
|||||||
/*
|
/*
|
||||||
* This is virtually a string class.
|
* This is virtually a string class.
|
||||||
* It covers std::string under the hood.
|
* It covers std::string under the hood.
|
||||||
|
*
|
||||||
|
* It deliberately does not provide c_str(), back(), find(str, pos), replace(),
|
||||||
|
* or substr(): the library must not rely on them. Do not add members here
|
||||||
|
* without checking that the library actually needs them.
|
||||||
*/
|
*/
|
||||||
class alt_string
|
class alt_string
|
||||||
{
|
{
|
||||||
@@ -106,11 +112,6 @@ class alt_string
|
|||||||
return str_impl < op.str_impl;
|
return str_impl < op.str_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* c_str() const
|
|
||||||
{
|
|
||||||
return str_impl.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
char& operator[](std::size_t index)
|
char& operator[](std::size_t index)
|
||||||
{
|
{
|
||||||
return str_impl[index];
|
return str_impl[index];
|
||||||
@@ -121,16 +122,6 @@ class alt_string
|
|||||||
return str_impl[index];
|
return str_impl[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
char& back()
|
|
||||||
{
|
|
||||||
return str_impl.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char& back() const
|
|
||||||
{
|
|
||||||
return str_impl.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
str_impl.clear();
|
str_impl.clear();
|
||||||
@@ -146,28 +137,11 @@ class alt_string
|
|||||||
return str_impl.empty();
|
return str_impl.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t find(const alt_string& str, std::size_t pos = 0) const
|
|
||||||
{
|
|
||||||
return str_impl.find(str.str_impl, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t find_first_of(char c, std::size_t pos = 0) const
|
std::size_t find_first_of(char c, std::size_t pos = 0) const
|
||||||
{
|
{
|
||||||
return str_impl.find_first_of(c, pos);
|
return str_impl.find_first_of(c, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
alt_string substr(std::size_t pos = 0, std::size_t count = npos) const
|
|
||||||
{
|
|
||||||
const std::string s = str_impl.substr(pos, count);
|
|
||||||
return {s.data(), s.size()};
|
|
||||||
}
|
|
||||||
|
|
||||||
alt_string& replace(std::size_t pos, std::size_t count, const alt_string& str)
|
|
||||||
{
|
|
||||||
str_impl.replace(pos, count, str.str_impl);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve( std::size_t new_cap = 0 )
|
void reserve( std::size_t new_cap = 0 )
|
||||||
{
|
{
|
||||||
str_impl.reserve(new_cap);
|
str_impl.reserve(new_cap);
|
||||||
@@ -202,6 +176,31 @@ bool operator<(const char* op1, const alt_string& op2) noexcept
|
|||||||
|
|
||||||
TEST_CASE("alternative string type")
|
TEST_CASE("alternative string type")
|
||||||
{
|
{
|
||||||
|
SECTION("binary formats")
|
||||||
|
{
|
||||||
|
alt_json doc;
|
||||||
|
doc["pi"] = 3.141;
|
||||||
|
doc["happy"] = true;
|
||||||
|
doc["list"] = {1, 2, 3};
|
||||||
|
|
||||||
|
CHECK(alt_json::from_cbor(alt_json::to_cbor(doc)) == doc);
|
||||||
|
CHECK(alt_json::from_msgpack(alt_json::to_msgpack(doc)) == doc);
|
||||||
|
// BSON is not covered: it additionally needs string_t::find(value_type),
|
||||||
|
// which alt_string does not provide
|
||||||
|
CHECK(alt_json::from_ubjson(alt_json::to_ubjson(doc)) == doc);
|
||||||
|
|
||||||
|
// a UBJSON high-precision number is parsed into a std::string that the
|
||||||
|
// reader has to hand to the SAX interface as an alt_string
|
||||||
|
const std::vector<uint8_t> high_precision =
|
||||||
|
{
|
||||||
|
'H', 'i', 0x16, '3', '.', '1', '4', '1', '5', '9', '2', '6', '5', '3',
|
||||||
|
'5', '8', '9', '7', '9', '3', '2', '3', '8', '4', '6'
|
||||||
|
};
|
||||||
|
const auto number = alt_json::from_ubjson(high_precision);
|
||||||
|
CHECK(number.is_number_float());
|
||||||
|
CHECK(number.get<double>() == doctest::Approx(3.14159265358979323846));
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("dump")
|
SECTION("dump")
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -332,6 +331,15 @@ TEST_CASE("alternative string type")
|
|||||||
|
|
||||||
CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]);
|
CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]);
|
||||||
CHECK(j.at(alt_json::json_pointer("/foo/1")) == j["foo"][1]);
|
CHECK(j.at(alt_json::json_pointer("/foo/1")) == j["foo"][1]);
|
||||||
|
|
||||||
|
// RFC 6901 escaping works without string_t::find(str, pos), replace(),
|
||||||
|
// and substr()
|
||||||
|
auto j2 = alt_json::parse(R"({"a/b": 1, "m~n": 2, "~/~~//": 3})");
|
||||||
|
CHECK(j2.at(alt_json::json_pointer("/a~1b")) == 1);
|
||||||
|
CHECK(j2.at(alt_json::json_pointer("/m~0n")) == 2);
|
||||||
|
CHECK(j2.at(alt_json::json_pointer("/~0~1~0~0~1~1")) == 3);
|
||||||
|
CHECK(alt_json::json_pointer("/~0~1~0~0~1~1").to_string() == alt_string("/~0~1~0~0~1~1"));
|
||||||
|
CHECK(j2.flatten().unflatten() == j2);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("patch")
|
SECTION("patch")
|
||||||
|
|||||||
@@ -326,57 +326,6 @@ TEST_CASE("lexicographical comparison operators")
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("integer/float mixed comparison is exact")
|
|
||||||
{
|
|
||||||
// Widening the integer to a double loses precision past the
|
|
||||||
// mantissa, so 2^63-2 and 2^63-1 both used to compare equal to the
|
|
||||||
// double 2^63 while differing from each other. That makes equality
|
|
||||||
// intransitive and the ordering not a strict weak ordering.
|
|
||||||
const json below_two_63 = static_cast<std::int64_t>(9223372036854775806LL);
|
|
||||||
const json max_int64 = (std::numeric_limits<std::int64_t>::max)();
|
|
||||||
const json two_63 = 9223372036854775808.0;
|
|
||||||
|
|
||||||
CHECK_FALSE(below_two_63 == two_63);
|
|
||||||
CHECK_FALSE(max_int64 == two_63);
|
|
||||||
CHECK(below_two_63 != max_int64);
|
|
||||||
CHECK(below_two_63 < max_int64);
|
|
||||||
CHECK(below_two_63 < two_63);
|
|
||||||
CHECK(max_int64 < two_63);
|
|
||||||
CHECK(two_63 > max_int64);
|
|
||||||
CHECK_FALSE(two_63 < max_int64);
|
|
||||||
|
|
||||||
// the same past the unsigned range
|
|
||||||
const json max_uint64 = (std::numeric_limits<std::uint64_t>::max)();
|
|
||||||
const json two_64 = 18446744073709551616.0;
|
|
||||||
CHECK_FALSE(max_uint64 == two_64);
|
|
||||||
CHECK(max_uint64 < two_64);
|
|
||||||
CHECK(two_64 > max_uint64);
|
|
||||||
|
|
||||||
// values a double represents exactly still compare equal
|
|
||||||
CHECK(json(1) == json(1.0));
|
|
||||||
CHECK(json(1u) == json(1.0));
|
|
||||||
CHECK(json(-3) == json(-3.0));
|
|
||||||
CHECK(json(1) < json(1.5));
|
|
||||||
CHECK(json(1.5) < json(2));
|
|
||||||
CHECK(json(2) > json(1.5));
|
|
||||||
|
|
||||||
// a NaN operand stays unordered against either integer kind
|
|
||||||
CHECK_FALSE(json(1) == json(nan));
|
|
||||||
CHECK_FALSE(json(1) < json(nan));
|
|
||||||
CHECK_FALSE(json(nan) < json(1));
|
|
||||||
CHECK_FALSE(json(1u) == json(nan));
|
|
||||||
|
|
||||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
|
||||||
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
|
||||||
CHECK((max_int64 <=> two_63) == std::partial_ordering::less); // *NOPAD*
|
|
||||||
CHECK((two_63 <=> max_int64) == std::partial_ordering::greater); // *NOPAD*
|
|
||||||
CHECK((below_two_63 <=> max_int64) == std::partial_ordering::less); // *NOPAD*
|
|
||||||
CHECK((max_uint64 <=> two_64) == std::partial_ordering::less); // *NOPAD*
|
|
||||||
CHECK((json(1) <=> json(1.0)) == std::partial_ordering::equivalent); // *NOPAD*
|
|
||||||
CHECK((json(1) <=> json(nan)) == std::partial_ordering::unordered); // *NOPAD*
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("compares unordered")
|
SECTION("compares unordered")
|
||||||
{
|
{
|
||||||
std::vector<std::vector<bool>> expected =
|
std::vector<std::vector<bool>> expected =
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||||
|
// | | |__ | | | | | | version 3.12.0
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "doctest_compatibility.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
// std::deque has no capacity() member function, which the library only needs
|
||||||
|
// to detect a reallocation for JSON_DIAGNOSTICS
|
||||||
|
using deque_json = nlohmann::basic_json<std::map, std::deque>;
|
||||||
|
|
||||||
|
// a std::vector whose at() is hidden: the library performs its own bounds
|
||||||
|
// check and must not fall back to the container's checked accessor
|
||||||
|
template<class T, class Allocator = std::allocator<T>>
|
||||||
|
class vector_without_at : public std::vector<T, Allocator>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
vector_without_at() = default;
|
||||||
|
|
||||||
|
// the array of an initializer list is built from a range
|
||||||
|
template<class InputIt>
|
||||||
|
vector_without_at(InputIt first, InputIt last) : std::vector<T, Allocator>(first, last) {}
|
||||||
|
|
||||||
|
void at() = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
using no_at_json = nlohmann::basic_json<std::map, vector_without_at>;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_CASE("array type without capacity()")
|
||||||
|
{
|
||||||
|
SECTION("the iterators take their exception specification from the container")
|
||||||
|
{
|
||||||
|
// basic_json's iterators move exactly as the container iterators do:
|
||||||
|
// their move operations are defaulted without a declared noexcept,
|
||||||
|
// because an array or object type whose iterator is not nothrow move
|
||||||
|
// constructible would otherwise have them deleted (std::deque's is not
|
||||||
|
// with libstdc++ before 11, and neither are MSVC's debug iterators)
|
||||||
|
CHECK(std::is_nothrow_move_constructible<nlohmann::json::iterator>::value ==
|
||||||
|
(std::is_nothrow_move_constructible<nlohmann::json::object_t::iterator>::value
|
||||||
|
&& std::is_nothrow_move_constructible<nlohmann::json::array_t::iterator>::value));
|
||||||
|
CHECK(std::is_nothrow_move_assignable<nlohmann::json::iterator>::value ==
|
||||||
|
(std::is_nothrow_move_assignable<nlohmann::json::object_t::iterator>::value
|
||||||
|
&& std::is_nothrow_move_assignable<nlohmann::json::array_t::iterator>::value));
|
||||||
|
CHECK(std::is_nothrow_move_constructible<nlohmann::json::const_iterator>::value ==
|
||||||
|
(std::is_nothrow_move_constructible<nlohmann::json::object_t::const_iterator>::value
|
||||||
|
&& std::is_nothrow_move_constructible<nlohmann::json::array_t::const_iterator>::value));
|
||||||
|
|
||||||
|
// and they are movable at all, which is what dropping the declared
|
||||||
|
// noexcept buys for a std::deque array
|
||||||
|
CHECK(std::is_move_constructible<deque_json::iterator>::value);
|
||||||
|
CHECK(std::is_move_assignable<deque_json::iterator>::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("adding elements")
|
||||||
|
{
|
||||||
|
deque_json j = deque_json::array();
|
||||||
|
j.push_back(1);
|
||||||
|
j.push_back("two");
|
||||||
|
j.emplace_back(3);
|
||||||
|
j += 4;
|
||||||
|
|
||||||
|
CHECK(j.size() == 4);
|
||||||
|
CHECK(j == deque_json({1, "two", 3, 4}));
|
||||||
|
CHECK(j.back() == 4);
|
||||||
|
CHECK(j.front() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("accessing and modifying elements")
|
||||||
|
{
|
||||||
|
auto j = deque_json::parse(R"([1,2,3])");
|
||||||
|
|
||||||
|
CHECK(j[1] == 2);
|
||||||
|
CHECK(j.at(2) == 3);
|
||||||
|
|
||||||
|
// growing through operator[] fills up with null values
|
||||||
|
j[5] = 6;
|
||||||
|
CHECK(j.size() == 6);
|
||||||
|
CHECK(j[4].is_null());
|
||||||
|
CHECK(j[5] == 6);
|
||||||
|
|
||||||
|
j.erase(0);
|
||||||
|
CHECK(j == deque_json({2, 3, nullptr, nullptr, 6}));
|
||||||
|
|
||||||
|
auto it = j.erase(j.begin());
|
||||||
|
CHECK(*it == 3);
|
||||||
|
|
||||||
|
j.insert(j.begin(), 1);
|
||||||
|
CHECK(j.front() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("serialization and deserialization")
|
||||||
|
{
|
||||||
|
const auto j = deque_json::parse(R"({"a":[1,[2,3]],"b":[]})");
|
||||||
|
CHECK(j.dump() == R"({"a":[1,[2,3]],"b":[]})");
|
||||||
|
CHECK(deque_json::parse(j.dump()) == j);
|
||||||
|
CHECK(deque_json::from_cbor(deque_json::to_cbor(j)) == j);
|
||||||
|
|
||||||
|
// empty containers are flattened to null and cannot be restored
|
||||||
|
const auto nested = deque_json::parse(R"({"a":[1,[2,3]]})");
|
||||||
|
CHECK(nested.flatten().unflatten() == nested);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("references stay valid while the array grows")
|
||||||
|
{
|
||||||
|
deque_json j = deque_json::array();
|
||||||
|
j.push_back(1);
|
||||||
|
auto& first = j[0];
|
||||||
|
for (int i = 0; i < 100; ++i)
|
||||||
|
{
|
||||||
|
j.push_back(i);
|
||||||
|
}
|
||||||
|
CHECK(&first == &j[0]);
|
||||||
|
CHECK(first == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("array type without at()")
|
||||||
|
{
|
||||||
|
// built in memory rather than parsed, so that the exception message does
|
||||||
|
// not gain a byte range with JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
no_at_json j = {1, 2, 3};
|
||||||
|
const auto& jc = j;
|
||||||
|
|
||||||
|
CHECK(j.at(0) == 1);
|
||||||
|
CHECK(j.at(2) == 3);
|
||||||
|
CHECK(jc.at(2) == 3);
|
||||||
|
|
||||||
|
CHECK_THROWS_WITH_AS(j.at(3), "[json.exception.out_of_range.401] array index 3 is out of range", no_at_json::out_of_range);
|
||||||
|
CHECK_THROWS_WITH_AS(jc.at(3), "[json.exception.out_of_range.401] array index 3 is out of range", no_at_json::out_of_range);
|
||||||
|
|
||||||
|
CHECK(j.at(no_at_json::json_pointer("/1")) == 2);
|
||||||
|
CHECK_THROWS_AS(j.at(no_at_json::json_pointer("/3")), no_at_json::out_of_range);
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||||
|
// | | |__ | | | | | | version 3.12.0
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "doctest_compatibility.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef JSON_HAS_CPP_17
|
||||||
|
#include <cstddef>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
// a BinaryType whose value type is signed: the elements must still be
|
||||||
|
// processed as the numbers 0..255
|
||||||
|
using char_binary_json = nlohmann::basic_json <
|
||||||
|
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
|
||||||
|
double, std::allocator, nlohmann::adl_serializer, std::vector<char>, void >;
|
||||||
|
|
||||||
|
#ifdef JSON_HAS_CPP_17
|
||||||
|
// a BinaryType whose value type is not an integer type at all
|
||||||
|
using byte_binary_json = nlohmann::basic_json <
|
||||||
|
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
|
||||||
|
double, std::allocator, nlohmann::adl_serializer, std::vector<std::byte>, void >;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_CASE("binary type whose value type is not std::uint8_t")
|
||||||
|
{
|
||||||
|
SECTION("a signed value type does not dump negative numbers")
|
||||||
|
{
|
||||||
|
const std::vector<char> chars{'\0', '\x01', '\xFF'};
|
||||||
|
CHECK(char_binary_json::binary(chars).dump() == R"({"bytes":[0,1,255],"subtype":null})");
|
||||||
|
CHECK(char_binary_json::binary(chars, 42).dump() == R"({"bytes":[0,1,255],"subtype":42})");
|
||||||
|
CHECK(char_binary_json::binary({}).dump() == R"({"bytes":[],"subtype":null})");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("the default binary type is unchanged")
|
||||||
|
{
|
||||||
|
CHECK(nlohmann::json::binary({0, 1, 255}, 42).dump() == R"({"bytes":[0,1,255],"subtype":42})");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JSON_HAS_CPP_17
|
||||||
|
SECTION("dumping a value type that is not an integer")
|
||||||
|
{
|
||||||
|
const std::vector<std::byte> bytes{std::byte{0}, std::byte{1}, std::byte{0xFF}};
|
||||||
|
CHECK(byte_binary_json::binary(bytes).dump() == R"({"bytes":[0,1,255],"subtype":null})");
|
||||||
|
CHECK(byte_binary_json::binary(bytes, 42).dump() == R"({"bytes":[0,1,255],"subtype":42})");
|
||||||
|
CHECK(byte_binary_json::binary({}).dump() == R"({"bytes":[],"subtype":null})");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("hashing and the binary formats")
|
||||||
|
{
|
||||||
|
const std::vector<std::byte> bytes{std::byte{0}, std::byte{1}, std::byte{0xFF}};
|
||||||
|
const auto j = byte_binary_json::binary(bytes);
|
||||||
|
|
||||||
|
CHECK(std::hash<byte_binary_json> {}(j) == std::hash<byte_binary_json> {}(j));
|
||||||
|
CHECK(byte_binary_json::from_cbor(byte_binary_json::to_cbor(j)) == j);
|
||||||
|
CHECK(byte_binary_json::from_msgpack(byte_binary_json::to_msgpack(j)) == j);
|
||||||
|
|
||||||
|
// UBJSON has no binary type, so binary values are written as an array
|
||||||
|
CHECK(byte_binary_json::from_ubjson(byte_binary_json::to_ubjson(j)) == byte_binary_json({0, 1, 255}));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||||
|
// | | |__ | | | | | | version 3.12.0
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "doctest_compatibility.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
// An ObjectType that does *not* define a key_compare member type, which is
|
||||||
|
// what every hash map looks like to the library.
|
||||||
|
//
|
||||||
|
// A hash map is deliberately not used here: object_t is probed for
|
||||||
|
// key_compare inside the definition of basic_json, that is, while basic_json
|
||||||
|
// is still an incomplete type, and whether a hash map can be instantiated
|
||||||
|
// with an incomplete mapped type depends on the standard library (libstdc++ 9
|
||||||
|
// needs the size of the mapped type for its node type and rejects it). So the
|
||||||
|
// object type wraps a std::map instead of inheriting from it: an earlier
|
||||||
|
// version derived from std::map and shadowed the inherited key_compare type
|
||||||
|
// with a same-named member function, relying on ordinary member hiding to
|
||||||
|
// make key_compare unreachable as a type. MSVC 2017 (AppVeyor, /std:c++17)
|
||||||
|
// does not honor that hiding for a typename-qualified lookup performed from
|
||||||
|
// outside the class and still resolves key_compare to the base's comparator
|
||||||
|
// type, so the library's probe incorrectly found one. Composition sidesteps
|
||||||
|
// the question entirely: with no base class, there is no key_compare to find
|
||||||
|
// under any lookup rule.
|
||||||
|
template<class Key, class T, class Compare, class Allocator>
|
||||||
|
class no_key_compare_map
|
||||||
|
{
|
||||||
|
using map_t = std::map<Key, T, Compare, Allocator>;
|
||||||
|
map_t data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type = typename map_t::key_type;
|
||||||
|
using mapped_type = typename map_t::mapped_type;
|
||||||
|
using value_type = typename map_t::value_type;
|
||||||
|
using size_type = typename map_t::size_type;
|
||||||
|
using allocator_type = typename map_t::allocator_type;
|
||||||
|
using iterator = typename map_t::iterator;
|
||||||
|
using const_iterator = typename map_t::const_iterator;
|
||||||
|
|
||||||
|
// -Weffc++ asks for the member to be initialized in the member
|
||||||
|
// initialization list, which a defaulted constructor does not do; the
|
||||||
|
// exception specification a defaulted one would have carried has to be
|
||||||
|
// written out as well, or -Wnoexcept objects where the standard library
|
||||||
|
// takes noexcept(construct(...))
|
||||||
|
no_key_compare_map() noexcept(std::is_nothrow_default_constructible<map_t>::value) : data() {}
|
||||||
|
|
||||||
|
// converting between two basic_json types builds the object from a range
|
||||||
|
template<class InputIt>
|
||||||
|
no_key_compare_map(InputIt first, InputIt last) : data(first, last) {}
|
||||||
|
|
||||||
|
iterator begin() noexcept
|
||||||
|
{
|
||||||
|
return data.begin();
|
||||||
|
}
|
||||||
|
iterator end() noexcept
|
||||||
|
{
|
||||||
|
return data.end();
|
||||||
|
}
|
||||||
|
const_iterator begin() const noexcept
|
||||||
|
{
|
||||||
|
return data.begin();
|
||||||
|
}
|
||||||
|
const_iterator end() const noexcept
|
||||||
|
{
|
||||||
|
return data.end();
|
||||||
|
}
|
||||||
|
const_iterator cbegin() const noexcept
|
||||||
|
{
|
||||||
|
return data.cbegin();
|
||||||
|
}
|
||||||
|
const_iterator cend() const noexcept
|
||||||
|
{
|
||||||
|
return data.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const noexcept
|
||||||
|
{
|
||||||
|
return data.empty();
|
||||||
|
}
|
||||||
|
size_type size() const noexcept
|
||||||
|
{
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
size_type max_size() const noexcept
|
||||||
|
{
|
||||||
|
return data.max_size();
|
||||||
|
}
|
||||||
|
void clear() noexcept
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find(const key_type& key)
|
||||||
|
{
|
||||||
|
return data.find(key);
|
||||||
|
}
|
||||||
|
const_iterator find(const key_type& key) const
|
||||||
|
{
|
||||||
|
return data.find(key);
|
||||||
|
}
|
||||||
|
size_type count(const key_type& key) const
|
||||||
|
{
|
||||||
|
return data.count(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> emplace(const key_type& key, const mapped_type& value)
|
||||||
|
{
|
||||||
|
return data.emplace(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> insert(const value_type& value)
|
||||||
|
{
|
||||||
|
return data.insert(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class InputIt>
|
||||||
|
void insert(InputIt first, InputIt last)
|
||||||
|
{
|
||||||
|
data.insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_type& operator[](const key_type& key)
|
||||||
|
{
|
||||||
|
return data[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_type& at(const key_type& key)
|
||||||
|
{
|
||||||
|
return data.at(key);
|
||||||
|
}
|
||||||
|
const mapped_type& at(const key_type& key) const
|
||||||
|
{
|
||||||
|
return data.at(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(iterator pos)
|
||||||
|
{
|
||||||
|
return data.erase(pos);
|
||||||
|
}
|
||||||
|
iterator erase(iterator first, iterator last)
|
||||||
|
{
|
||||||
|
return data.erase(first, last);
|
||||||
|
}
|
||||||
|
size_type erase(const key_type& key)
|
||||||
|
{
|
||||||
|
return data.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(no_key_compare_map& other) noexcept(noexcept(data.swap(other.data)))
|
||||||
|
{
|
||||||
|
data.swap(other.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const no_key_compare_map& lhs, const no_key_compare_map& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data == rhs.data;
|
||||||
|
}
|
||||||
|
friend bool operator<(const no_key_compare_map& lhs, const no_key_compare_map& rhs)
|
||||||
|
{
|
||||||
|
return lhs.data < rhs.data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using no_key_compare_json = nlohmann::basic_json<no_key_compare_map>;
|
||||||
|
|
||||||
|
// An ObjectType whose erase(iterator) returns void rather than the following
|
||||||
|
// iterator, as for instance Abseil's hash maps do
|
||||||
|
template<class Key, class T, class Compare, class Allocator>
|
||||||
|
struct void_erase_map : std::map<Key, T, Compare, Allocator>
|
||||||
|
{
|
||||||
|
using base_t = std::map<Key, T, Compare, Allocator>;
|
||||||
|
using iterator = typename base_t::iterator;
|
||||||
|
using base_t::erase;
|
||||||
|
|
||||||
|
void erase(iterator pos)
|
||||||
|
{
|
||||||
|
base_t::erase(pos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using void_erase_json = nlohmann::basic_json<void_erase_map>;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_CASE("object type whose erase() returns void")
|
||||||
|
{
|
||||||
|
SECTION("erasing every element through the returned iterator")
|
||||||
|
{
|
||||||
|
void_erase_json j;
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
j["k" + std::to_string(i)] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t erased = 0;
|
||||||
|
for (auto it = j.begin(); it != j.end(); ++erased)
|
||||||
|
{
|
||||||
|
it = j.erase(it);
|
||||||
|
}
|
||||||
|
CHECK(erased == 8);
|
||||||
|
CHECK(j.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("erasing in the middle returns the following element")
|
||||||
|
{
|
||||||
|
void_erase_json j;
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
j["k" + std::to_string(i)] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = j.begin();
|
||||||
|
++it;
|
||||||
|
const auto after = j.erase(it);
|
||||||
|
CHECK(j.size() == 3);
|
||||||
|
CHECK(after.key() == "k2");
|
||||||
|
CHECK(after.value() == 2);
|
||||||
|
CHECK(!j.contains("k1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("the other erase overloads are unaffected")
|
||||||
|
{
|
||||||
|
void_erase_json j;
|
||||||
|
j["a"] = 1;
|
||||||
|
j["b"] = 2;
|
||||||
|
j["c"] = 3;
|
||||||
|
|
||||||
|
CHECK(j.erase("a") == 1);
|
||||||
|
CHECK(j.erase("nope") == 0);
|
||||||
|
j.erase(j.begin(), j.end());
|
||||||
|
CHECK(j.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("object type without key_compare")
|
||||||
|
{
|
||||||
|
SECTION("object_comparator_t falls back to default_object_comparator_t")
|
||||||
|
{
|
||||||
|
CHECK(std::is_same < no_key_compare_json::object_comparator_t,
|
||||||
|
no_key_compare_json::default_object_comparator_t >::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("object types defining key_compare are unaffected")
|
||||||
|
{
|
||||||
|
CHECK(std::is_same<nlohmann::json::object_comparator_t,
|
||||||
|
nlohmann::json::object_t::key_compare>::value);
|
||||||
|
CHECK(std::is_same<nlohmann::ordered_json::object_comparator_t,
|
||||||
|
nlohmann::ordered_json::object_t::key_compare>::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("creating and accessing values")
|
||||||
|
{
|
||||||
|
no_key_compare_json j;
|
||||||
|
j["one"] = 1;
|
||||||
|
j["two"] = "zwei";
|
||||||
|
j["three"]["nested"] = true;
|
||||||
|
|
||||||
|
CHECK(j.size() == 3);
|
||||||
|
CHECK(j.at("one") == 1);
|
||||||
|
CHECK(j["two"] == "zwei");
|
||||||
|
CHECK(j["three"]["nested"] == true);
|
||||||
|
CHECK(j.contains("one"));
|
||||||
|
CHECK(!j.contains("four"));
|
||||||
|
CHECK(j.find("one") != j.end());
|
||||||
|
CHECK(j.count("one") == 1);
|
||||||
|
CHECK(j.erase("one") == 1);
|
||||||
|
CHECK(j.size() == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("serialization and deserialization")
|
||||||
|
{
|
||||||
|
const auto j = no_key_compare_json::parse(R"({"a":[1,2,3],"b":{"c":null}})");
|
||||||
|
CHECK(j["a"].size() == 3);
|
||||||
|
CHECK(j["a"][2] == 3);
|
||||||
|
CHECK(j["b"]["c"].is_null());
|
||||||
|
CHECK(no_key_compare_json::parse(j.dump()) == j);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("binary formats")
|
||||||
|
{
|
||||||
|
const auto j = no_key_compare_json::parse(R"({"a":[1,2,3],"b":"x"})");
|
||||||
|
CHECK(no_key_compare_json::from_cbor(no_key_compare_json::to_cbor(j)) == j);
|
||||||
|
CHECK(no_key_compare_json::from_msgpack(no_key_compare_json::to_msgpack(j)) == j);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("flatten and unflatten")
|
||||||
|
{
|
||||||
|
// "o" has a key that looks like an array index, so unflatten() must
|
||||||
|
// not turn it into an array
|
||||||
|
const auto j = no_key_compare_json::parse(
|
||||||
|
R"({"c":[1,2,3],"d":{"e":"s"},"n":[[0,1],[2]],"o":{"2":"x"}})");
|
||||||
|
CHECK(j.flatten().unflatten() == j);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("conversion to and from nlohmann::json")
|
||||||
|
{
|
||||||
|
const auto j = no_key_compare_json::parse(R"({"a":1,"b":[true,null]})");
|
||||||
|
const nlohmann::json converted(j);
|
||||||
|
|
||||||
|
CHECK(converted.is_object());
|
||||||
|
CHECK(converted["a"] == 1);
|
||||||
|
CHECK(converted["b"][0] == true);
|
||||||
|
CHECK(converted["b"][1].is_null());
|
||||||
|
CHECK(no_key_compare_json(converted) == j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -273,36 +273,5 @@ TEST_CASE("Regression tests for extended diagnostics")
|
|||||||
CHECK(j1["numbers"]["two"] == 2);
|
CHECK(j1["numbers"]["two"] == 2);
|
||||||
CHECK(j1["string"] == "t");
|
CHECK(j1["string"] == "t");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Regression test - swap(array_t&)/swap(object_t&) must update JSON_DIAGNOSTICS parent pointers")
|
|
||||||
{
|
|
||||||
// swap(array_t&)
|
|
||||||
{
|
|
||||||
json j = json::array();
|
|
||||||
json::array_t arr = {json::array({1})};
|
|
||||||
j.swap(arr);
|
|
||||||
|
|
||||||
// parent pointers of the moved-in elements must point into j, not
|
|
||||||
// into the now-defunct free-standing array_t
|
|
||||||
CHECK_THROWS_WITH_AS(j[0][0].get<std::string>(), "[json.exception.type_error.302] (/0/0) type must be string, but is number", json::type_error);
|
|
||||||
|
|
||||||
// must not trigger assert_invariant() in a debug/assert-enabled build
|
|
||||||
json const k = j;
|
|
||||||
CHECK(k == j);
|
|
||||||
}
|
|
||||||
|
|
||||||
// swap(object_t&)
|
|
||||||
{
|
|
||||||
json o = json::object();
|
|
||||||
json::object_t obj = {{"a", json::array({1})}};
|
|
||||||
o.swap(obj);
|
|
||||||
|
|
||||||
CHECK_THROWS_WITH_AS(o["a"][0].get<std::string>(), "[json.exception.type_error.302] (/a/0) type must be string, but is number", json::type_error);
|
|
||||||
|
|
||||||
// must not trigger assert_invariant() in a debug/assert-enabled build
|
|
||||||
json const p = o;
|
|
||||||
CHECK(p == o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1388,84 +1388,3 @@ TEST_CASE("JSON patch - add to a primitive parent (regression #4292)")
|
|||||||
CHECK_THROWS_AS(doc.patch(patch), json::out_of_range&);
|
CHECK_THROWS_AS(doc.patch(patch), json::out_of_range&);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("JSON patch - diff emits array removals in descending index order")
|
|
||||||
{
|
|
||||||
SECTION("array shrunk to empty")
|
|
||||||
{
|
|
||||||
json const source = {0, 1, 2, 3, 4};
|
|
||||||
json const target = json::array();
|
|
||||||
|
|
||||||
json const patch = json::diff(source, target);
|
|
||||||
|
|
||||||
json const expected = R"(
|
|
||||||
[
|
|
||||||
{"op": "remove", "path": "/4"},
|
|
||||||
{"op": "remove", "path": "/3"},
|
|
||||||
{"op": "remove", "path": "/2"},
|
|
||||||
{"op": "remove", "path": "/1"},
|
|
||||||
{"op": "remove", "path": "/0"}
|
|
||||||
]
|
|
||||||
)"_json;
|
|
||||||
|
|
||||||
CHECK(patch == expected);
|
|
||||||
CHECK(source.patch(patch) == target);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("array partially shrunk, after a replacement at a common index")
|
|
||||||
{
|
|
||||||
json const source = {0, 1, 2, 3, 4};
|
|
||||||
json const target = {0, 9};
|
|
||||||
|
|
||||||
json const patch = json::diff(source, target);
|
|
||||||
|
|
||||||
// the replacement comes first, then the removals, highest index first
|
|
||||||
json const expected = R"(
|
|
||||||
[
|
|
||||||
{"op": "replace", "path": "/1", "value": 9},
|
|
||||||
{"op": "remove", "path": "/4"},
|
|
||||||
{"op": "remove", "path": "/3"},
|
|
||||||
{"op": "remove", "path": "/2"}
|
|
||||||
]
|
|
||||||
)"_json;
|
|
||||||
|
|
||||||
CHECK(patch == expected);
|
|
||||||
CHECK(source.patch(patch) == target);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("nested array shrunk")
|
|
||||||
{
|
|
||||||
json const source = {{"a", {0, 1, 2}}};
|
|
||||||
json const target = {{"a", json::array()}};
|
|
||||||
|
|
||||||
json const patch = json::diff(source, target);
|
|
||||||
|
|
||||||
json const expected = R"(
|
|
||||||
[
|
|
||||||
{"op": "remove", "path": "/a/2"},
|
|
||||||
{"op": "remove", "path": "/a/1"},
|
|
||||||
{"op": "remove", "path": "/a/0"}
|
|
||||||
]
|
|
||||||
)"_json;
|
|
||||||
|
|
||||||
CHECK(patch == expected);
|
|
||||||
CHECK(source.patch(patch) == target);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("many removals still round-trip")
|
|
||||||
{
|
|
||||||
json source = json::array();
|
|
||||||
for (int i = 0; i < 1000; ++i)
|
|
||||||
{
|
|
||||||
source.push_back(i);
|
|
||||||
}
|
|
||||||
json const target = json::array();
|
|
||||||
|
|
||||||
json const patch = json::diff(source, target);
|
|
||||||
|
|
||||||
CHECK(patch.size() == 1000);
|
|
||||||
CHECK(patch.front().at("path") == "/999");
|
|
||||||
CHECK(patch.back().at("path") == "/0");
|
|
||||||
CHECK(source.patch(patch) == target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -465,6 +465,16 @@ TEST_CASE("JSON pointers")
|
|||||||
// explicit roundtrip check
|
// explicit roundtrip check
|
||||||
CHECK(j.flatten().unflatten() == j);
|
CHECK(j.flatten().unflatten() == j);
|
||||||
|
|
||||||
|
// an object is only unflattened to an array if one of its keys is the
|
||||||
|
// reference token 0; this must not depend on which key is seen first
|
||||||
|
CHECK(json({{"/2", "x"}}).unflatten() == json({{"2", "x"}}));
|
||||||
|
CHECK(json({{"/10", "y"}, {"/2", "z"}}).unflatten() == json({{"10", "y"}, {"2", "z"}}));
|
||||||
|
CHECK(json({{"/0", 1}, {"/1", 2}}).unflatten() == json({1, 2}));
|
||||||
|
CHECK(json({{"/1", 2}, {"/0", 1}}).unflatten() == json({1, 2}));
|
||||||
|
CHECK(json({{"/0", 1}, {"/2", 3}}).unflatten() == json({1, nullptr, 3}));
|
||||||
|
CHECK(json({{"/a/1", 2}, {"/a/0", 1}}).unflatten() == json({{"a", {1, 2}}}));
|
||||||
|
CHECK(json({{"/a/1", 2}, {"/a/x", 1}}).unflatten() == json({{"a", {{"1", 2}, {"x", 1}}}}));
|
||||||
|
|
||||||
// roundtrip for primitive values
|
// roundtrip for primitive values
|
||||||
json j_null;
|
json j_null;
|
||||||
CHECK(j_null.flatten().unflatten() == j_null);
|
CHECK(j_null.flatten().unflatten() == j_null);
|
||||||
|
|||||||
@@ -81,84 +81,3 @@ TEST_CASE("regression test for issue #3732 - iteration_proxy_value<iter_impl<ord
|
|||||||
};
|
};
|
||||||
static_cast<void>(fn);
|
static_cast<void>(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("regression test - diff() must account for ordered_json member order")
|
|
||||||
{
|
|
||||||
SECTION("pure reorder, no value changes")
|
|
||||||
{
|
|
||||||
ordered_json a = {{"a", 1}, {"b", 2}};
|
|
||||||
ordered_json b = {{"b", 2}, {"a", 1}};
|
|
||||||
CHECK(a != b); // order-sensitive equality
|
|
||||||
CHECK(a.patch(ordered_json::diff(a, b)) == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("new key must land at the front")
|
|
||||||
{
|
|
||||||
ordered_json c = {{"b", 2}};
|
|
||||||
ordered_json e = {{"a", 1}, {"b", 2}};
|
|
||||||
CHECK(c.patch(ordered_json::diff(c, e)) == e);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("reorder plus a value change on one of the reordered keys")
|
|
||||||
{
|
|
||||||
ordered_json a = {{"a", 1}, {"b", 2}};
|
|
||||||
ordered_json b = {{"b", 20}, {"a", 1}};
|
|
||||||
CHECK(a != b);
|
|
||||||
CHECK(a.patch(ordered_json::diff(a, b)) == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("reorder plus a deleted key")
|
|
||||||
{
|
|
||||||
ordered_json a = {{"a", 1}, {"b", 2}, {"c", 3}};
|
|
||||||
ordered_json b = {{"b", 2}, {"a", 1}};
|
|
||||||
CHECK(a != b);
|
|
||||||
CHECK(a.patch(ordered_json::diff(a, b)) == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("reorder plus a nested value that itself needs a recursive diff")
|
|
||||||
{
|
|
||||||
ordered_json a = {{"a", {{"x", 1}, {"y", 2}}}, {"b", 2}};
|
|
||||||
ordered_json b = {{"b", 2}, {"a", {{"x", 1}, {"y", 99}}}};
|
|
||||||
CHECK(a != b);
|
|
||||||
CHECK(a.patch(ordered_json::diff(a, b)) == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("three or more keys shuffled into a different order")
|
|
||||||
{
|
|
||||||
ordered_json a = {{"a", 1}, {"b", 2}, {"c", 3}, {"d", 4}};
|
|
||||||
ordered_json b = {{"d", 4}, {"b", 2}, {"a", 1}, {"c", 3}};
|
|
||||||
CHECK(a != b);
|
|
||||||
CHECK(a.patch(ordered_json::diff(a, b)) == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("matching order still produces a minimal patch (fast path unaffected)")
|
|
||||||
{
|
|
||||||
ordered_json a = {{"a", 1}, {"b", 2}, {"c", 3}};
|
|
||||||
ordered_json b = {{"a", 1}, {"b", 20}, {"c", 3}};
|
|
||||||
auto p = ordered_json::diff(a, b);
|
|
||||||
// only the changed value should be touched, not a wholesale remove+add
|
|
||||||
CHECK(p.size() == 1);
|
|
||||||
CHECK(p[0]["op"] == "replace");
|
|
||||||
CHECK(p[0]["path"] == "/b");
|
|
||||||
CHECK(a.patch(p) == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("plain json (std::map-backed) is unaffected by same-key-different-insertion-order")
|
|
||||||
{
|
|
||||||
json a;
|
|
||||||
a["b"] = 2;
|
|
||||||
a["a"] = 1;
|
|
||||||
|
|
||||||
json b;
|
|
||||||
b["a"] = 1;
|
|
||||||
b["b"] = 2;
|
|
||||||
|
|
||||||
// std::map iteration is always sorted by key, so a == b regardless of
|
|
||||||
// insertion order, and diff() must still produce the same minimal
|
|
||||||
// (empty) result as before this fix
|
|
||||||
CHECK(a == b);
|
|
||||||
auto p = json::diff(a, b);
|
|
||||||
CHECK(p.empty());
|
|
||||||
CHECK(a.patch(p) == b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1566,101 +1566,4 @@ TEST_CASE("issue #5402 - update(merge_objects=true) overwrites a primitive with
|
|||||||
CHECK(mixed == json({{"keep", {{"a", 1}, {"b", 2}}}, {"replace", {{"x", 2}}}}));
|
CHECK(mixed == json({{"keep", {{"a", 1}, {"b", 2}}}, {"replace", {{"x", 2}}}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("regression test - parser callback must not lose a duplicate key's prior value")
|
|
||||||
{
|
|
||||||
// a callback that rejects only the scalar value 2
|
|
||||||
const json::parser_callback_t drop_value_2 = [](int /*depth*/, json::parse_event_t ev, json & v)
|
|
||||||
{
|
|
||||||
return !(ev == json::parse_event_t::value && v == 2);
|
|
||||||
};
|
|
||||||
|
|
||||||
SECTION("duplicate key, second (scalar) value rejected - prior value is restored")
|
|
||||||
{
|
|
||||||
const json j = json::parse(R"({"a":1,"a":2})", drop_value_2);
|
|
||||||
CHECK(j.dump() == "{\"a\":1}");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("duplicate key, second value is an object rejected at object_end - prior value is restored")
|
|
||||||
{
|
|
||||||
const json j = json::parse(R"({"a":1,"a":{"x":2}})",
|
|
||||||
[](int depth, json::parse_event_t ev, json& /*parsed*/)
|
|
||||||
{
|
|
||||||
return !(ev == json::parse_event_t::object_end && depth == 1);
|
|
||||||
});
|
|
||||||
CHECK(j.dump() == "{\"a\":1}");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("duplicate key, second value is an array rejected at array_end - prior value is restored")
|
|
||||||
{
|
|
||||||
const json j = json::parse(R"({"a":1,"a":[9,9]})",
|
|
||||||
[](int depth, json::parse_event_t ev, json& /*parsed*/)
|
|
||||||
{
|
|
||||||
return !(ev == json::parse_event_t::array_end && depth == 1);
|
|
||||||
});
|
|
||||||
CHECK(j.dump() == "{\"a\":1}");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("duplicate key, second value accepted (scalar) - last value wins")
|
|
||||||
{
|
|
||||||
const json j = json::parse(R"({"a":1,"a":2})", [](int, json::parse_event_t, json&) noexcept
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
CHECK(j.dump() == "{\"a\":2}");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("duplicate key, second value accepted (object) - last value wins")
|
|
||||||
{
|
|
||||||
const json j = json::parse(R"({"a":1,"a":{"x":2}})", [](int, json::parse_event_t, json&) noexcept
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
CHECK(j.dump() == "{\"a\":{\"x\":2}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("brand new (non-duplicate) key, value rejected - member is fully absent")
|
|
||||||
{
|
|
||||||
const json j = json::parse(R"({"a":1,"b":2})", drop_value_2);
|
|
||||||
CHECK(j.dump() == "{\"a\":1}");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("duplicate key nested two levels deep")
|
|
||||||
{
|
|
||||||
const json j = json::parse(R"({"outer":{"a":1,"a":2}})", drop_value_2);
|
|
||||||
CHECK(j.dump() == "{\"outer\":{\"a\":1}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("three occurrences of the same key - middle rejected, last accepted")
|
|
||||||
{
|
|
||||||
const json j = json::parse(R"({"k":1,"k":2,"k":3})", drop_value_2);
|
|
||||||
CHECK(j.dump() == "{\"k\":3}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("regression test - excessive binary container size honors allow_exceptions=false")
|
|
||||||
{
|
|
||||||
// CBOR array with declared length 2^63
|
|
||||||
const std::vector<std::uint8_t> cbor = {0x9b, 0x80, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
// CBOR map with declared length 2^63
|
|
||||||
const std::vector<std::uint8_t> cbor_m = {0xbb, 0x80, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
// UBJSON array with declared length 2^63-1
|
|
||||||
const std::vector<std::uint8_t> ubj = {'[', '#', 'L', 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
|
||||||
// BJData array with declared length 2^63-1 (little endian)
|
|
||||||
const std::vector<std::uint8_t> bjd = {'[', '#', 'L', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f};
|
|
||||||
|
|
||||||
// allow_exceptions=false must report failure instead of throwing/aborting
|
|
||||||
CHECK(json::from_cbor(cbor, true, false).is_discarded());
|
|
||||||
CHECK(json::from_cbor(cbor_m, true, false).is_discarded());
|
|
||||||
CHECK(json::from_ubjson(ubj, true, false).is_discarded());
|
|
||||||
CHECK(json::from_bjdata(bjd, true, false).is_discarded());
|
|
||||||
|
|
||||||
// allow_exceptions=true (the default) must still throw exactly as before
|
|
||||||
CHECK_THROWS_AS(json::from_cbor(cbor), json::out_of_range);
|
|
||||||
CHECK_THROWS_WITH(json::from_cbor(cbor),
|
|
||||||
"[json.exception.out_of_range.408] excessive array size: 9223372036854775808");
|
|
||||||
|
|
||||||
// regression guard: a genuinely truncated CBOR input must remain discarded
|
|
||||||
CHECK(json::from_cbor(std::vector<std::uint8_t> {0x9b, 0, 0, 0, 0, 0, 0, 0, 0x02}, true, false).is_discarded());
|
|
||||||
}
|
|
||||||
|
|
||||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||||
|
|||||||
Reference in New Issue
Block a user