* support JSON Merge Patch (RFC 7396) diff creation The JSON merge patch document format describes the set of modifications to a resource's content, that more closely mimics the syntax of the resource being modified. However, and in contrast to JSON Patch (RFC 6902), a JSON Merge Patch cannot express certain modifications, e.g., changing an array element at a specific index, or setting a specific object value to null. The null value in a JSON Merge Patch is used to remove the key from the object. The diff algorithm is not part of the RFC 7396, but it was tested against all examples provided, plus additional cases on how null values are handled. Signed-off-by: Luís Murta <luis@murta.dev> * improve algorithm efficiency Signed-off-by: Luís Murta <luis@murta.dev> * fix inconsistent nulls and empty arrays Also add CHECKs for the patch, documentation and run `make amalgamate`. Signed-off-by: Luís Murta <luis@murta.dev> * documentation cleanups Signed-off-by: Luís Murta <luis@murta.dev> * add an iterative fallback to merge_diff Bound the recursion depth like diff() and merge_patch(), and test values nested past the bound. Signed-off-by: Luís Murta <luis@murta.dev> * address the remaining review comments Signed-off-by: Luís Murta <luis@murta.dev> * move multi-line raw strings out of CHECK macros GCC 4.8/5, ICPC and NVHPC mis-tokenize multi-line raw string literals inside macro arguments, breaking the build or the parsed JSON. Signed-off-by: Luís Murta <luis@murta.dev> --------- Signed-off-by: Luís Murta <luis@murta.dev>
2.8 KiB
nlohmann::basic_json::merge_diff
static basic_json merge_diff(const basic_json& source,
const basic_json& target);
Creates a JSON Merge Patch so that value source can be changed into the value
target by calling the merge_patch function. The patch contains only what differs: changed and
added members with their new values, and removed members with the value #!json null. Nested objects are compared
member by member; any other value that differs, including an array, is replaced as a whole.
For two JSON values source and target, where target contains no object member whose value is #!json null, the
following code always yields #!cpp true:
basic_json patched = source;
patched.merge_patch(merge_diff(source, target));
patched == target;
Parameters
source(in)- JSON value to compare from
target(in)- JSON value to compare against
Return value
a JSON Merge Patch to convert the source to target
Exception safety
Strong guarantee: source and target are never modified.
Complexity
Linear in the total number of values (including nested ones) in source and target, times the cost of a key-based
object operation (looking up a key, or adding one to the patch): logarithmic for json, and linear for
ordered_json (see ordered_map complexity). For
ordered_json, diffing two objects with n and m members therefore takes O((n+m)²).
Notes
- A merge patch uses
#!json nullto remove a member, so it cannot set a member to#!json null. As in RFC 7396, a#!json nullmember oftargetis treated as absent: the patch removes the member fromsourceinstead of setting it to#!json null. A member that is#!json nullin bothsourceandtargetis unchanged and left out of the patch, sosourcekeeps it. - A merge patch cannot reorder object members, and
merge_patchappends added members at the end. Forordered_json, the patched value therefore has the same members astarget, but not necessarily in the same order, and may compare unequal to it. The patch lists changed and removed members in the order ofsource, followed by added members in the order oftarget.
Examples
??? example
The following code shows how a JSON Merge Patch is created as a diff for two JSON values.
```cpp
--8<-- "examples/merge_diff.cpp"
```
Output:
```json
--8<-- "examples/merge_diff.output"
```
See also
- RFC 7396 (JSON Merge Patch)
- merge_patch applies a JSON Merge Patch
- diff creates a diff as a JSON Patch
Version history
- Added in version 3.13.0.