! @brief creates a diff as a JSON patch Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can be changed into the value @a target by calling @ref patch function. @invariant For two JSON values @a source and @a target, the following code yields always `true`: @code {.cpp} source.patch(diff(source, target)) == target; @endcode @note Currently
| 24955 | @since version 2.0.0 |
| 24956 | */ |
| 24957 | JSON_HEDLEY_WARN_UNUSED_RESULT |
| 24958 | static basic_json diff(const basic_json& source, const basic_json& target, |
| 24959 | const std::string& path = "") |
| 24960 | { |
| 24961 | // the patch |
| 24962 | basic_json result(value_t::array); |
| 24963 | |
| 24964 | // if the values are the same, return empty patch |
| 24965 | if (source == target) |
| 24966 | { |
| 24967 | return result; |
| 24968 | } |
| 24969 | |
| 24970 | if (source.type() != target.type()) |
| 24971 | { |
| 24972 | // different types: replace value |
| 24973 | result.push_back( |
| 24974 | { |
| 24975 | {"op", "replace"}, {"path", path}, {"value", target} |
| 24976 | }); |
| 24977 | return result; |
| 24978 | } |
| 24979 | |
| 24980 | switch (source.type()) |
| 24981 | { |
| 24982 | case value_t::array: |
| 24983 | { |
| 24984 | // first pass: traverse common elements |
| 24985 | std::size_t i = 0; |
| 24986 | while (i < source.size() && i < target.size()) |
| 24987 | { |
| 24988 | // recursive call to compare array values at index i |
| 24989 | auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); |
| 24990 | result.insert(result.end(), temp_diff.begin(), temp_diff.end()); |
| 24991 | ++i; |
| 24992 | } |
| 24993 | |
| 24994 | // i now reached the end of at least one array |
| 24995 | // in a second pass, traverse the remaining elements |
| 24996 | |
| 24997 | // remove my remaining elements |
| 24998 | const auto end_index = static_cast<difference_type>(result.size()); |
| 24999 | while (i < source.size()) |
| 25000 | { |
| 25001 | // add operations in reverse order to avoid invalid |
| 25002 | // indices |
| 25003 | result.insert(result.begin() + end_index, object( |
| 25004 | { |
| 25005 | {"op", "remove"}, |
| 25006 | {"path", path + "/" + std::to_string(i)} |
| 25007 | })); |
| 25008 | ++i; |
| 25009 | } |
| 25010 | |
| 25011 | // add other remaining elements |
| 25012 | while (i < target.size()) |
| 25013 | { |
| 25014 | result.push_back( |