cleanup, test, and diff
This commit is contained in:
		
							parent
							
								
									96cfe7463f
								
							
						
					
					
						commit
						5e0bf75d60
					
				
					 10 changed files with 2068 additions and 716 deletions
				
			
		| 
						 | 
				
			
			@ -428,7 +428,7 @@ $ make
 | 
			
		|||
$ ./json_unit "*"
 | 
			
		||||
 | 
			
		||||
===============================================================================
 | 
			
		||||
All tests passed (3344416 assertions in 30 test cases)
 | 
			
		||||
All tests passed (3344554 assertions in 31 test cases)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								doc/examples/diff.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								doc/examples/diff.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
#include <json.hpp>
 | 
			
		||||
 | 
			
		||||
using json = nlohmann::json;
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    // the source document
 | 
			
		||||
    json source = R"(
 | 
			
		||||
        {
 | 
			
		||||
            "baz": "qux",
 | 
			
		||||
            "foo": "bar"
 | 
			
		||||
        }
 | 
			
		||||
    )"_json;
 | 
			
		||||
 | 
			
		||||
    // the target document
 | 
			
		||||
    json target = R"(
 | 
			
		||||
        {
 | 
			
		||||
            "baz": "boo",
 | 
			
		||||
            "hello": [
 | 
			
		||||
                "world"
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    )"_json;
 | 
			
		||||
 | 
			
		||||
    // create the patch
 | 
			
		||||
    json patch = json::diff(source, target);
 | 
			
		||||
 | 
			
		||||
    // roundtrip
 | 
			
		||||
    json patched_source = source.patch(patch);
 | 
			
		||||
 | 
			
		||||
    // output patch and roundtrip result
 | 
			
		||||
    std::cout << std::setw(4) << patch << "\n\n"
 | 
			
		||||
              << std::setw(4) << patched_source << std::endl;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								doc/examples/diff.link
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								doc/examples/diff.link
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<a target="_blank" href="http://melpon.org/wandbox/permlink/hicmeOK39tBxaluM"><b>online</b></a>
 | 
			
		||||
							
								
								
									
										25
									
								
								doc/examples/diff.output
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								doc/examples/diff.output
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
[
 | 
			
		||||
    {
 | 
			
		||||
        "op": "replace",
 | 
			
		||||
        "path": "/baz",
 | 
			
		||||
        "value": "boo"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "op": "remove",
 | 
			
		||||
        "path": "/foo"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "op": "add",
 | 
			
		||||
        "path": "/hello",
 | 
			
		||||
        "value": [
 | 
			
		||||
            "world"
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    "baz": "boo",
 | 
			
		||||
    "hello": [
 | 
			
		||||
        "world"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										30
									
								
								doc/examples/patch.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								doc/examples/patch.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
#include <json.hpp>
 | 
			
		||||
 | 
			
		||||
using json = nlohmann::json;
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    // the original document
 | 
			
		||||
    json doc = R"(
 | 
			
		||||
        {
 | 
			
		||||
          "baz": "qux",
 | 
			
		||||
          "foo": "bar"
 | 
			
		||||
        }
 | 
			
		||||
    )"_json;
 | 
			
		||||
 | 
			
		||||
    // the patch
 | 
			
		||||
    json patch = R"(
 | 
			
		||||
        [
 | 
			
		||||
          { "op": "replace", "path": "/baz", "value": "boo" },
 | 
			
		||||
          { "op": "add", "path": "/hello", "value": ["world"] },
 | 
			
		||||
          { "op": "remove", "path": "/foo"}
 | 
			
		||||
        ]
 | 
			
		||||
    )"_json;
 | 
			
		||||
 | 
			
		||||
    // apply the patch
 | 
			
		||||
    json patched_doc = doc.patch(patch);
 | 
			
		||||
 | 
			
		||||
    // output original and patched document
 | 
			
		||||
    std::cout << std::setw(4) << doc << "\n\n"
 | 
			
		||||
              << std::setw(4) << patched_doc << std::endl;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								doc/examples/patch.link
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								doc/examples/patch.link
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<a target="_blank" href="http://melpon.org/wandbox/permlink/lbczW3AzcUbH1Nbo"><b>online</b></a>
 | 
			
		||||
							
								
								
									
										11
									
								
								doc/examples/patch.output
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								doc/examples/patch.output
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
{
 | 
			
		||||
    "baz": "qux",
 | 
			
		||||
    "foo": "bar"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    "baz": "boo",
 | 
			
		||||
    "hello": [
 | 
			
		||||
        "world"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										679
									
								
								src/json.hpp
									
										
									
									
									
								
							
							
						
						
									
										679
									
								
								src/json.hpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -3595,121 +3595,6 @@ class basic_json
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
 | 
			
		||||
    No bound checking is performed. Similar to
 | 
			
		||||
    @ref operator[](const typename object_t::key_type&), `null` values
 | 
			
		||||
    are created in arrays and objects if necessary.
 | 
			
		||||
 | 
			
		||||
    In particular:
 | 
			
		||||
    - If the JSON pointer points to an object key that does not exist, it
 | 
			
		||||
      is created an filled with a `null` value before a reference to it
 | 
			
		||||
      is returned.
 | 
			
		||||
    - If the JSON pointer points to an array index that does not exist, it
 | 
			
		||||
      is created an filled with a `null` value before a reference to it
 | 
			
		||||
      is returned. All indices between the current maximum and the given
 | 
			
		||||
      index are also filled with `null`.
 | 
			
		||||
    - The special value `-` is treated as a synonym for the index past the
 | 
			
		||||
      end.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  a JSON pointer
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,operatorjson_pointer}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    reference operator[](const json_pointer& ptr)
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_unchecked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
 | 
			
		||||
    No bound checking is performed. The function does not change the JSON
 | 
			
		||||
    value; no `null` values are created. In particular, the the special value
 | 
			
		||||
    `-` yields an exception.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return const reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    const_reference operator[](const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_unchecked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Returns a reference to the element at with specified JSON pointer @a ptr,
 | 
			
		||||
    with bounds checking.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,at_json_pointer}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    reference at(const json_pointer& ptr)
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_checked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Returns a const reference to the element at with specified JSON pointer
 | 
			
		||||
    @a ptr, with bounds checking.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,at_json_pointer_const}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    const_reference at(const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_checked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified object element with default value
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4145,8 +4030,8 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @throw std::domain_error when called on a type other than JSON array;
 | 
			
		||||
    example: `"cannot use erase() with null"`
 | 
			
		||||
    @throw std::out_of_range when `idx >= size()`; example: `"index out of
 | 
			
		||||
    range"`
 | 
			
		||||
    @throw std::out_of_range when `idx >= size()`; example: `"array index 17
 | 
			
		||||
    is out of range"`
 | 
			
		||||
 | 
			
		||||
    @complexity Linear in distance between @a idx and the end of the container.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4167,7 +4052,7 @@ class basic_json
 | 
			
		|||
        {
 | 
			
		||||
            if (idx >= size())
 | 
			
		||||
            {
 | 
			
		||||
                throw std::out_of_range("index out of range");
 | 
			
		||||
                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            assert(m_value.array != nullptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -8969,9 +8854,17 @@ basic_json_parser_63:
 | 
			
		|||
            : reference_tokens(split(s))
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        /// test for inequality
 | 
			
		||||
        bool operator!=(const json_pointer& rhs) const
 | 
			
		||||
        {
 | 
			
		||||
            return reference_tokens != rhs.reference_tokens;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      private:
 | 
			
		||||
        /// remove and return last reference pointer
 | 
			
		||||
        std::string pop_back()
 | 
			
		||||
        {
 | 
			
		||||
            if (reference_tokens.empty())
 | 
			
		||||
            if (is_root())
 | 
			
		||||
            {
 | 
			
		||||
                throw std::domain_error("JSON pointer has no parent");
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -8981,7 +8874,24 @@ basic_json_parser_63:
 | 
			
		|||
            return last;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      private:
 | 
			
		||||
        /// return whether pointer points to the root document
 | 
			
		||||
        bool is_root() const
 | 
			
		||||
        {
 | 
			
		||||
            return reference_tokens.empty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        json_pointer top() const
 | 
			
		||||
        {
 | 
			
		||||
            if (is_root())
 | 
			
		||||
            {
 | 
			
		||||
                throw std::domain_error("JSON pointer has no parent");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            json_pointer result = *this;
 | 
			
		||||
            result.reference_tokens = {reference_tokens[0]};
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*!
 | 
			
		||||
        @brief create and return a reference to the pointed to value
 | 
			
		||||
        */
 | 
			
		||||
| 
						 | 
				
			
			@ -9020,7 +8930,7 @@ basic_json_parser_63:
 | 
			
		|||
                    case value_t::array:
 | 
			
		||||
                    {
 | 
			
		||||
                        // create an entry in the array
 | 
			
		||||
                        result = &result->operator[](static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                        result = &result->operator[](static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9083,7 +8993,7 @@ basic_json_parser_63:
 | 
			
		|||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            // convert array index to number; unchecked access
 | 
			
		||||
                            ptr = &ptr->operator[](static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                            ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -9128,7 +9038,7 @@ basic_json_parser_63:
 | 
			
		|||
                        }
 | 
			
		||||
 | 
			
		||||
                        // note: at performs range check
 | 
			
		||||
                        ptr = &ptr->at(static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                        ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9180,7 +9090,7 @@ basic_json_parser_63:
 | 
			
		|||
                        }
 | 
			
		||||
 | 
			
		||||
                        // use unchecked array access
 | 
			
		||||
                        ptr = &ptr->operator[](static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                        ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9224,7 +9134,7 @@ basic_json_parser_63:
 | 
			
		|||
                        }
 | 
			
		||||
 | 
			
		||||
                        // note: at performs range check
 | 
			
		||||
                        ptr = &ptr->at(static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                        ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9291,12 +9201,8 @@ basic_json_parser_63:
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // first transform any occurrence of the sequence '~1' to '/'
 | 
			
		||||
                replace_substring(reference_token, "~1", "/");
 | 
			
		||||
                // then transform any occurrence of the sequence '~0' to '~'
 | 
			
		||||
                replace_substring(reference_token, "~0", "~");
 | 
			
		||||
 | 
			
		||||
                // finally, store the reference token
 | 
			
		||||
                unescape(reference_token);
 | 
			
		||||
                result.push_back(reference_token);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9332,6 +9238,24 @@ basic_json_parser_63:
 | 
			
		|||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// escape tilde and slash
 | 
			
		||||
        static std::string escape(std::string s)
 | 
			
		||||
        {
 | 
			
		||||
            // escape "~"" to "~0" and "/" to "~1"
 | 
			
		||||
            replace_substring(s, "~", "~0");
 | 
			
		||||
            replace_substring(s, "/", "~1");
 | 
			
		||||
            return s;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// unescape tilde and slash
 | 
			
		||||
        static void unescape(std::string& s)
 | 
			
		||||
        {
 | 
			
		||||
            // first transform any occurrence of the sequence '~1' to '/'
 | 
			
		||||
            replace_substring(s, "~1", "/");
 | 
			
		||||
            // then transform any occurrence of the sequence '~0' to '~'
 | 
			
		||||
            replace_substring(s, "~0", "~");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*!
 | 
			
		||||
        @param[in] reference_string  the reference string to the current value
 | 
			
		||||
        @param[in] value             the value to consider
 | 
			
		||||
| 
						 | 
				
			
			@ -9339,7 +9263,7 @@ basic_json_parser_63:
 | 
			
		|||
 | 
			
		||||
        @note Empty objects or arrays are flattened to `null`.
 | 
			
		||||
        */
 | 
			
		||||
        static void flatten(const std::string reference_string,
 | 
			
		||||
        static void flatten(const std::string& reference_string,
 | 
			
		||||
                            const basic_json& value,
 | 
			
		||||
                            basic_json& result)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -9376,12 +9300,7 @@ basic_json_parser_63:
 | 
			
		|||
                        // iterate object and use keys as reference string
 | 
			
		||||
                        for (const auto& element : *value.m_value.object)
 | 
			
		||||
                        {
 | 
			
		||||
                            // escape "~"" to "~0" and "/" to "~1"
 | 
			
		||||
                            std::string key(element.first);
 | 
			
		||||
                            replace_substring(key, "~", "~0");
 | 
			
		||||
                            replace_substring(key, "/", "~1");
 | 
			
		||||
 | 
			
		||||
                            flatten(reference_string + "/" + key,
 | 
			
		||||
                            flatten(reference_string + "/" + escape(element.first),
 | 
			
		||||
                                    element.second, result);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -9435,13 +9354,128 @@ basic_json_parser_63:
 | 
			
		|||
        std::vector<std::string> reference_tokens {};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ////////////////////////////
 | 
			
		||||
    // JSON Pointer functions //
 | 
			
		||||
    ////////////////////////////
 | 
			
		||||
    //////////////////////////
 | 
			
		||||
    // JSON Pointer support //
 | 
			
		||||
    //////////////////////////
 | 
			
		||||
 | 
			
		||||
    /// @name JSON Pointer functions
 | 
			
		||||
    /// @{
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
 | 
			
		||||
    No bound checking is performed. Similar to
 | 
			
		||||
    @ref operator[](const typename object_t::key_type&), `null` values
 | 
			
		||||
    are created in arrays and objects if necessary.
 | 
			
		||||
 | 
			
		||||
    In particular:
 | 
			
		||||
    - If the JSON pointer points to an object key that does not exist, it
 | 
			
		||||
      is created an filled with a `null` value before a reference to it
 | 
			
		||||
      is returned.
 | 
			
		||||
    - If the JSON pointer points to an array index that does not exist, it
 | 
			
		||||
      is created an filled with a `null` value before a reference to it
 | 
			
		||||
      is returned. All indices between the current maximum and the given
 | 
			
		||||
      index are also filled with `null`.
 | 
			
		||||
    - The special value `-` is treated as a synonym for the index past the
 | 
			
		||||
      end.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  a JSON pointer
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,operatorjson_pointer}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    reference operator[](const json_pointer& ptr)
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_unchecked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
 | 
			
		||||
    No bound checking is performed. The function does not change the JSON
 | 
			
		||||
    value; no `null` values are created. In particular, the the special value
 | 
			
		||||
    `-` yields an exception.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return const reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    const_reference operator[](const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_unchecked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Returns a reference to the element at with specified JSON pointer @a ptr,
 | 
			
		||||
    with bounds checking.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,at_json_pointer}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    reference at(const json_pointer& ptr)
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_checked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Returns a const reference to the element at with specified JSON pointer
 | 
			
		||||
    @a ptr, with bounds checking.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,at_json_pointer_const}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    const_reference at(const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_checked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief return flattened JSON value
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9505,35 +9539,119 @@ basic_json_parser_63:
 | 
			
		|||
 | 
			
		||||
    /// @}
 | 
			
		||||
 | 
			
		||||
    //////////////////////////
 | 
			
		||||
    // JSON Patch functions //
 | 
			
		||||
    //////////////////////////
 | 
			
		||||
 | 
			
		||||
    /// @name JSON Patch functions
 | 
			
		||||
    /// @{
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief applies a JSON patch
 | 
			
		||||
 | 
			
		||||
    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
 | 
			
		||||
    expressing a sequence of operations to apply to a JSON) document. With
 | 
			
		||||
    this funcion, a JSON Patch is applied to the current JSON value by
 | 
			
		||||
    executing all operations from the patch.
 | 
			
		||||
 | 
			
		||||
    @param[in] patch  JSON patch document
 | 
			
		||||
    @return patched document
 | 
			
		||||
 | 
			
		||||
    @note The original JSON value is not changed; that is, the patch is
 | 
			
		||||
          applied to a copy of the value.
 | 
			
		||||
    @note The application of a patch is atomic: Either all operations succeed
 | 
			
		||||
          and the patched document is returned or an exception is thrown. In
 | 
			
		||||
          any case, the original value is not changed: the patch is applied
 | 
			
		||||
          to a copy of the value.
 | 
			
		||||
 | 
			
		||||
    @sa [RFC 6902](https://tools.ietf.org/html/rfc6902)
 | 
			
		||||
    @throw std::out_of_range if a JSON pointer inside the patch could not
 | 
			
		||||
    be resolved successfully in the current JSON value; example: `"key baz
 | 
			
		||||
    not found"`
 | 
			
		||||
    @throw invalid_argument if the JSON patch is malformed (e.g., mandatory
 | 
			
		||||
    attributes are missing); example: `"operation add must have member path"`
 | 
			
		||||
 | 
			
		||||
    @complexity Linear in the size of the JSON value and the length of the
 | 
			
		||||
    JSON patch. As usually only a fraction of the JSON value is affected by
 | 
			
		||||
    the patch, the complexity can usually be neglected.
 | 
			
		||||
 | 
			
		||||
    @liveexample{The following code shows how a JSON patch is applied to a
 | 
			
		||||
    value.,patch}
 | 
			
		||||
 | 
			
		||||
    @sa @ref diff -- create a JSON patch by comparing two JSON values
 | 
			
		||||
 | 
			
		||||
    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
 | 
			
		||||
    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    basic_json apply_patch(const basic_json& patch) const
 | 
			
		||||
    basic_json patch(const basic_json& patch) const
 | 
			
		||||
    {
 | 
			
		||||
        // make a working copy to apply the patch to
 | 
			
		||||
        basic_json result = *this;
 | 
			
		||||
 | 
			
		||||
        // the valid JSON Patch operations
 | 
			
		||||
        enum class patch_operations {add, remove, replace, move, copy, test, invalid};
 | 
			
		||||
 | 
			
		||||
        const auto get_op = [](const std::string op)
 | 
			
		||||
        {
 | 
			
		||||
            if (op == "add")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::add;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "remove")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::remove;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "replace")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::replace;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "move")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::move;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "copy")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::copy;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "test")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::test;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return patch_operations::invalid;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // wrapper for "add" operation; add value at ptr
 | 
			
		||||
        const auto operation_add = [&result](json_pointer & ptr, basic_json val)
 | 
			
		||||
        {
 | 
			
		||||
            // adding to the root of the target document means replacing it
 | 
			
		||||
            if (ptr.is_root())
 | 
			
		||||
            {
 | 
			
		||||
                result = val;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // make sure the top element of the pointer exists
 | 
			
		||||
                json_pointer top_pointer = ptr.top();
 | 
			
		||||
                if (top_pointer != ptr)
 | 
			
		||||
                {
 | 
			
		||||
                    basic_json& x = result.at(top_pointer);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // get reference to parent of JSON pointer ptr
 | 
			
		||||
                const auto last_path = ptr.pop_back();
 | 
			
		||||
            basic_json& parent = result.at(ptr);
 | 
			
		||||
                basic_json& parent = result[ptr];
 | 
			
		||||
 | 
			
		||||
            if (parent.is_object())
 | 
			
		||||
                switch (parent.m_type)
 | 
			
		||||
                {
 | 
			
		||||
                    case value_t::null:
 | 
			
		||||
                    case value_t::object:
 | 
			
		||||
                    {
 | 
			
		||||
                        // use operator[] to add value
 | 
			
		||||
                        parent[last_path] = val;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
            else if (parent.is_array())
 | 
			
		||||
 | 
			
		||||
                    case value_t::array:
 | 
			
		||||
                    {
 | 
			
		||||
                        if (last_path == "-")
 | 
			
		||||
                        {
 | 
			
		||||
| 
						 | 
				
			
			@ -9541,9 +9659,26 @@ basic_json_parser_63:
 | 
			
		|||
                            parent.push_back(val);
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            const auto idx = std::stoi(last_path);
 | 
			
		||||
                            if (static_cast<size_type>(idx) > parent.size())
 | 
			
		||||
                            {
 | 
			
		||||
                                // avoid undefined behavior
 | 
			
		||||
                                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                // default case: insert add offset
 | 
			
		||||
                    parent.insert(parent.begin() + std::stoi(last_path), val);
 | 
			
		||||
                                parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    default:
 | 
			
		||||
                    {
 | 
			
		||||
                        throw std::domain_error("unexpected parent type " + parent.type_name());
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -9558,11 +9693,21 @@ basic_json_parser_63:
 | 
			
		|||
            // remove child
 | 
			
		||||
            if (parent.is_object())
 | 
			
		||||
            {
 | 
			
		||||
                parent.erase(parent.find(last_path));
 | 
			
		||||
                // perform range check
 | 
			
		||||
                auto it = parent.find(last_path);
 | 
			
		||||
                if (it != parent.end())
 | 
			
		||||
                {
 | 
			
		||||
                    parent.erase(it);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::out_of_range("key '" + last_path + "' not found");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if (parent.is_array())
 | 
			
		||||
            {
 | 
			
		||||
                parent.erase(parent.begin() + std::stoi(last_path));
 | 
			
		||||
                // note erase performs range check
 | 
			
		||||
                parent.erase(static_cast<size_type>(std::stoi(last_path)));
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9570,7 +9715,7 @@ basic_json_parser_63:
 | 
			
		|||
        if (not patch.is_array())
 | 
			
		||||
        {
 | 
			
		||||
            // a JSON patch must be an array of objects
 | 
			
		||||
            throw std::domain_error("JSON patch must be an array of objects");
 | 
			
		||||
            throw std::invalid_argument("JSON patch must be an array of objects");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // iterate and apply th eoperations
 | 
			
		||||
| 
						 | 
				
			
			@ -9590,13 +9735,13 @@ basic_json_parser_63:
 | 
			
		|||
                // check if desired value is present
 | 
			
		||||
                if (it == val.m_value.object->end())
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::domain_error(error_msg + " must have member '" + member + "'");
 | 
			
		||||
                    throw std::invalid_argument(error_msg + " must have member '" + member + "'");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // check if result is of type string
 | 
			
		||||
                if (string_type and not it->second.is_string())
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::domain_error(error_msg + " must have string member '" + member + "'");
 | 
			
		||||
                    throw std::invalid_argument(error_msg + " must have string member '" + member + "'");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // no error: return value
 | 
			
		||||
| 
						 | 
				
			
			@ -9606,7 +9751,7 @@ basic_json_parser_63:
 | 
			
		|||
            // type check
 | 
			
		||||
            if (not val.is_object())
 | 
			
		||||
            {
 | 
			
		||||
                throw std::domain_error("JSON patch must be an array of objects");
 | 
			
		||||
                throw std::invalid_argument("JSON patch must be an array of objects");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // collect mandatory members
 | 
			
		||||
| 
						 | 
				
			
			@ -9614,51 +9759,251 @@ basic_json_parser_63:
 | 
			
		|||
            const std::string path = get_value(op, "path", true);
 | 
			
		||||
            json_pointer ptr(path);
 | 
			
		||||
 | 
			
		||||
            if (op == "add")
 | 
			
		||||
            switch (get_op(op))
 | 
			
		||||
            {
 | 
			
		||||
                case patch_operations::add:
 | 
			
		||||
                {
 | 
			
		||||
                    operation_add(ptr, get_value("add", "value", false));
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "remove")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::remove:
 | 
			
		||||
                {
 | 
			
		||||
                    operation_remove(ptr);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "replace")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::replace:
 | 
			
		||||
                {
 | 
			
		||||
                    // the "path" location must exist - use at()
 | 
			
		||||
                    result.at(ptr) = get_value("replace", "value", false);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "move")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::move:
 | 
			
		||||
                {
 | 
			
		||||
                    const std::string from_path = get_value("move", "from", true);
 | 
			
		||||
                    json_pointer from_ptr(from_path);
 | 
			
		||||
                basic_json v = result[from_ptr];
 | 
			
		||||
 | 
			
		||||
                    // the "from" location must exist - use at()
 | 
			
		||||
                    basic_json v = result.at(from_ptr);
 | 
			
		||||
 | 
			
		||||
                    // The move operation is functionally identical to a
 | 
			
		||||
                    // "remove" operation on the "from" location, followed
 | 
			
		||||
                    // immediately by an "add" operation at the target
 | 
			
		||||
                    // location with the value that was just removed.
 | 
			
		||||
                    operation_remove(from_ptr);
 | 
			
		||||
                    operation_add(ptr, v);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "copy")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::copy:
 | 
			
		||||
                {
 | 
			
		||||
                    const std::string from_path = get_value("copy", "from", true);;
 | 
			
		||||
                    const json_pointer from_ptr(from_path);
 | 
			
		||||
 | 
			
		||||
                    // the "from" location must exist - use at()
 | 
			
		||||
                    result[ptr] = result.at(from_ptr);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "test")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::test:
 | 
			
		||||
                {
 | 
			
		||||
                if (result.at(ptr) != get_value("test", "value", false))
 | 
			
		||||
                    bool success = false;
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        // check if "value" matches the one at "path"
 | 
			
		||||
                        // the "path" location must exist - use at()
 | 
			
		||||
                        success = (result.at(ptr) == get_value("test", "value", false));
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (std::out_of_range&)
 | 
			
		||||
                    {
 | 
			
		||||
                        // ignore out of range errors: success remains false
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // throw an exception if test fails
 | 
			
		||||
                    if (not success)
 | 
			
		||||
                    {
 | 
			
		||||
                        throw std::domain_error("unsuccessful: " + val.dump());
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else
 | 
			
		||||
 | 
			
		||||
                case patch_operations::invalid:
 | 
			
		||||
                {
 | 
			
		||||
                    // op must be "add", "remove", "replace", "move", "copy", or
 | 
			
		||||
                    // "test"
 | 
			
		||||
                throw std::domain_error("operation value '" + op + "' is invalid");
 | 
			
		||||
                    throw std::invalid_argument("operation value '" + op + "' is invalid");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @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, only `remove`, `add`, and `replace` operations are
 | 
			
		||||
          generated.
 | 
			
		||||
 | 
			
		||||
    @param[in] source  JSON value to copare from
 | 
			
		||||
    @param[in] target  JSON value to copare against
 | 
			
		||||
    @param[in] path    helper value to create JSON pointers
 | 
			
		||||
 | 
			
		||||
    @return a JSON patch to convert the @a source to @a target
 | 
			
		||||
 | 
			
		||||
    @complexity Linear in the lengths of @a source and @a target.
 | 
			
		||||
 | 
			
		||||
    @liveexample{The following code shows how a JSON patch is created as a
 | 
			
		||||
    diff for two JSON values.,diff}
 | 
			
		||||
 | 
			
		||||
    @sa @ref patch -- apply a JSON patch
 | 
			
		||||
 | 
			
		||||
    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    static basic_json diff(const basic_json& source,
 | 
			
		||||
                           const basic_json& target,
 | 
			
		||||
                           std::string path = "") noexcept
 | 
			
		||||
    {
 | 
			
		||||
        // the patch
 | 
			
		||||
        basic_json result(value_t::array);
 | 
			
		||||
 | 
			
		||||
        // if the values are the same, return empty patch
 | 
			
		||||
        if (source == target)
 | 
			
		||||
        {
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (source.type() != target.type())
 | 
			
		||||
        {
 | 
			
		||||
            // different types: replace value
 | 
			
		||||
            result.push_back(
 | 
			
		||||
            {
 | 
			
		||||
                {"op", "replace"},
 | 
			
		||||
                {"path", path},
 | 
			
		||||
                {"value", target}
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            switch (source.type())
 | 
			
		||||
            {
 | 
			
		||||
                case value_t::array:
 | 
			
		||||
                {
 | 
			
		||||
                    // first pass: traverse common elements
 | 
			
		||||
                    size_t i = 0;
 | 
			
		||||
                    while (i < source.size() and i < target.size())
 | 
			
		||||
                    {
 | 
			
		||||
                        // recursive call to compare array values at index i
 | 
			
		||||
                        auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
 | 
			
		||||
                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());
 | 
			
		||||
                        ++i;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // i now reached the end of at least one array
 | 
			
		||||
                    // in a second pass, traverse the remaining elements
 | 
			
		||||
 | 
			
		||||
                    // remove my remaining elements
 | 
			
		||||
                    while (i < source.size())
 | 
			
		||||
                    {
 | 
			
		||||
                        result.push_back(object(
 | 
			
		||||
                        {
 | 
			
		||||
                            {"op", "remove"},
 | 
			
		||||
                            {"path", path + "/" + std::to_string(i)}
 | 
			
		||||
                        }));
 | 
			
		||||
                        ++i;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // add other remaining elements
 | 
			
		||||
                    while (i < target.size())
 | 
			
		||||
                    {
 | 
			
		||||
                        result.push_back(
 | 
			
		||||
                        {
 | 
			
		||||
                            {"op", "add"},
 | 
			
		||||
                            {"path", path + "/" + std::to_string(i)},
 | 
			
		||||
                            {"value", target[i]}
 | 
			
		||||
                        });
 | 
			
		||||
                        ++i;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
                    // first pass: traverse this object's elements
 | 
			
		||||
                    for (auto it = source.begin(); it != source.end(); ++it)
 | 
			
		||||
                    {
 | 
			
		||||
                        // escape the key name to be used in a JSON patch
 | 
			
		||||
                        const auto key = json_pointer::escape(it.key());
 | 
			
		||||
 | 
			
		||||
                        if (target.find(it.key()) != target.end())
 | 
			
		||||
                        {
 | 
			
		||||
                            // recursive call to compare object values at key it
 | 
			
		||||
                            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(
 | 
			
		||||
                            {
 | 
			
		||||
                                {"op", "remove"},
 | 
			
		||||
                                {"path", path + "/" + key}
 | 
			
		||||
                            }));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // second pass: traverse other object's elements
 | 
			
		||||
                    for (auto it = target.begin(); it != target.end(); ++it)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (source.find(it.key()) == source.end())
 | 
			
		||||
                        {
 | 
			
		||||
                            // found a key that is not in this -> add it
 | 
			
		||||
                            const auto key = json_pointer::escape(it.key());
 | 
			
		||||
                            result.push_back(
 | 
			
		||||
                            {
 | 
			
		||||
                                {"op", "add"},
 | 
			
		||||
                                {"path", path + "/" + key},
 | 
			
		||||
                                {"value", it.value()}
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                {
 | 
			
		||||
                    // both primitive type: replace value
 | 
			
		||||
                    result.push_back(
 | 
			
		||||
                    {
 | 
			
		||||
                        {"op", "replace"},
 | 
			
		||||
                        {"path", path},
 | 
			
		||||
                        {"value", target}
 | 
			
		||||
                    });
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9678,9 +10023,9 @@ using json = basic_json<>;
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/////////////////////////
 | 
			
		||||
// nonmember functions //
 | 
			
		||||
/////////////////////////
 | 
			
		||||
///////////////////////
 | 
			
		||||
// nonmember support //
 | 
			
		||||
///////////////////////
 | 
			
		||||
 | 
			
		||||
// specialization of std::swap, and std::hash
 | 
			
		||||
namespace std
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3595,121 +3595,6 @@ class basic_json
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
 | 
			
		||||
    No bound checking is performed. Similar to
 | 
			
		||||
    @ref operator[](const typename object_t::key_type&), `null` values
 | 
			
		||||
    are created in arrays and objects if necessary.
 | 
			
		||||
 | 
			
		||||
    In particular:
 | 
			
		||||
    - If the JSON pointer points to an object key that does not exist, it
 | 
			
		||||
      is created an filled with a `null` value before a reference to it
 | 
			
		||||
      is returned.
 | 
			
		||||
    - If the JSON pointer points to an array index that does not exist, it
 | 
			
		||||
      is created an filled with a `null` value before a reference to it
 | 
			
		||||
      is returned. All indices between the current maximum and the given
 | 
			
		||||
      index are also filled with `null`.
 | 
			
		||||
    - The special value `-` is treated as a synonym for the index past the
 | 
			
		||||
      end.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  a JSON pointer
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,operatorjson_pointer}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    reference operator[](const json_pointer& ptr)
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_unchecked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
 | 
			
		||||
    No bound checking is performed. The function does not change the JSON
 | 
			
		||||
    value; no `null` values are created. In particular, the the special value
 | 
			
		||||
    `-` yields an exception.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return const reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    const_reference operator[](const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_unchecked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Returns a reference to the element at with specified JSON pointer @a ptr,
 | 
			
		||||
    with bounds checking.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,at_json_pointer}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    reference at(const json_pointer& ptr)
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_checked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Returns a const reference to the element at with specified JSON pointer
 | 
			
		||||
    @a ptr, with bounds checking.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,at_json_pointer_const}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    const_reference at(const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_checked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified object element with default value
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4145,8 +4030,8 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @throw std::domain_error when called on a type other than JSON array;
 | 
			
		||||
    example: `"cannot use erase() with null"`
 | 
			
		||||
    @throw std::out_of_range when `idx >= size()`; example: `"index out of
 | 
			
		||||
    range"`
 | 
			
		||||
    @throw std::out_of_range when `idx >= size()`; example: `"array index 17
 | 
			
		||||
    is out of range"`
 | 
			
		||||
 | 
			
		||||
    @complexity Linear in distance between @a idx and the end of the container.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4167,7 +4052,7 @@ class basic_json
 | 
			
		|||
        {
 | 
			
		||||
            if (idx >= size())
 | 
			
		||||
            {
 | 
			
		||||
                throw std::out_of_range("index out of range");
 | 
			
		||||
                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            assert(m_value.array != nullptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -8279,9 +8164,17 @@ class basic_json
 | 
			
		|||
            : reference_tokens(split(s))
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        /// test for inequality
 | 
			
		||||
        bool operator!=(const json_pointer& rhs) const
 | 
			
		||||
        {
 | 
			
		||||
            return reference_tokens != rhs.reference_tokens;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      private:
 | 
			
		||||
        /// remove and return last reference pointer
 | 
			
		||||
        std::string pop_back()
 | 
			
		||||
        {
 | 
			
		||||
            if (reference_tokens.empty())
 | 
			
		||||
            if (is_root())
 | 
			
		||||
            {
 | 
			
		||||
                throw std::domain_error("JSON pointer has no parent");
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -8291,7 +8184,24 @@ class basic_json
 | 
			
		|||
            return last;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      private:
 | 
			
		||||
        /// return whether pointer points to the root document
 | 
			
		||||
        bool is_root() const
 | 
			
		||||
        {
 | 
			
		||||
            return reference_tokens.empty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        json_pointer top() const
 | 
			
		||||
        {
 | 
			
		||||
            if (is_root())
 | 
			
		||||
            {
 | 
			
		||||
                throw std::domain_error("JSON pointer has no parent");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            json_pointer result = *this;
 | 
			
		||||
            result.reference_tokens = {reference_tokens[0]};
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*!
 | 
			
		||||
        @brief create and return a reference to the pointed to value
 | 
			
		||||
        */
 | 
			
		||||
| 
						 | 
				
			
			@ -8330,7 +8240,7 @@ class basic_json
 | 
			
		|||
                    case value_t::array:
 | 
			
		||||
                    {
 | 
			
		||||
                        // create an entry in the array
 | 
			
		||||
                        result = &result->operator[](static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                        result = &result->operator[](static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8393,7 +8303,7 @@ class basic_json
 | 
			
		|||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            // convert array index to number; unchecked access
 | 
			
		||||
                            ptr = &ptr->operator[](static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                            ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -8438,7 +8348,7 @@ class basic_json
 | 
			
		|||
                        }
 | 
			
		||||
 | 
			
		||||
                        // note: at performs range check
 | 
			
		||||
                        ptr = &ptr->at(static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                        ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8490,7 +8400,7 @@ class basic_json
 | 
			
		|||
                        }
 | 
			
		||||
 | 
			
		||||
                        // use unchecked array access
 | 
			
		||||
                        ptr = &ptr->operator[](static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                        ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8534,7 +8444,7 @@ class basic_json
 | 
			
		|||
                        }
 | 
			
		||||
 | 
			
		||||
                        // note: at performs range check
 | 
			
		||||
                        ptr = &ptr->at(static_cast<size_t>(std::stoi(reference_token)));
 | 
			
		||||
                        ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8601,12 +8511,8 @@ class basic_json
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // first transform any occurrence of the sequence '~1' to '/'
 | 
			
		||||
                replace_substring(reference_token, "~1", "/");
 | 
			
		||||
                // then transform any occurrence of the sequence '~0' to '~'
 | 
			
		||||
                replace_substring(reference_token, "~0", "~");
 | 
			
		||||
 | 
			
		||||
                // finally, store the reference token
 | 
			
		||||
                unescape(reference_token);
 | 
			
		||||
                result.push_back(reference_token);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8642,6 +8548,24 @@ class basic_json
 | 
			
		|||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// escape tilde and slash
 | 
			
		||||
        static std::string escape(std::string s)
 | 
			
		||||
        {
 | 
			
		||||
            // escape "~"" to "~0" and "/" to "~1"
 | 
			
		||||
            replace_substring(s, "~", "~0");
 | 
			
		||||
            replace_substring(s, "/", "~1");
 | 
			
		||||
            return s;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// unescape tilde and slash
 | 
			
		||||
        static void unescape(std::string& s)
 | 
			
		||||
        {
 | 
			
		||||
            // first transform any occurrence of the sequence '~1' to '/'
 | 
			
		||||
            replace_substring(s, "~1", "/");
 | 
			
		||||
            // then transform any occurrence of the sequence '~0' to '~'
 | 
			
		||||
            replace_substring(s, "~0", "~");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*!
 | 
			
		||||
        @param[in] reference_string  the reference string to the current value
 | 
			
		||||
        @param[in] value             the value to consider
 | 
			
		||||
| 
						 | 
				
			
			@ -8649,7 +8573,7 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
        @note Empty objects or arrays are flattened to `null`.
 | 
			
		||||
        */
 | 
			
		||||
        static void flatten(const std::string reference_string,
 | 
			
		||||
        static void flatten(const std::string& reference_string,
 | 
			
		||||
                            const basic_json& value,
 | 
			
		||||
                            basic_json& result)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -8686,12 +8610,7 @@ class basic_json
 | 
			
		|||
                        // iterate object and use keys as reference string
 | 
			
		||||
                        for (const auto& element : *value.m_value.object)
 | 
			
		||||
                        {
 | 
			
		||||
                            // escape "~"" to "~0" and "/" to "~1"
 | 
			
		||||
                            std::string key(element.first);
 | 
			
		||||
                            replace_substring(key, "~", "~0");
 | 
			
		||||
                            replace_substring(key, "/", "~1");
 | 
			
		||||
 | 
			
		||||
                            flatten(reference_string + "/" + key,
 | 
			
		||||
                            flatten(reference_string + "/" + escape(element.first),
 | 
			
		||||
                                    element.second, result);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -8745,13 +8664,128 @@ class basic_json
 | 
			
		|||
        std::vector<std::string> reference_tokens {};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ////////////////////////////
 | 
			
		||||
    // JSON Pointer functions //
 | 
			
		||||
    ////////////////////////////
 | 
			
		||||
    //////////////////////////
 | 
			
		||||
    // JSON Pointer support //
 | 
			
		||||
    //////////////////////////
 | 
			
		||||
 | 
			
		||||
    /// @name JSON Pointer functions
 | 
			
		||||
    /// @{
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
 | 
			
		||||
    No bound checking is performed. Similar to
 | 
			
		||||
    @ref operator[](const typename object_t::key_type&), `null` values
 | 
			
		||||
    are created in arrays and objects if necessary.
 | 
			
		||||
 | 
			
		||||
    In particular:
 | 
			
		||||
    - If the JSON pointer points to an object key that does not exist, it
 | 
			
		||||
      is created an filled with a `null` value before a reference to it
 | 
			
		||||
      is returned.
 | 
			
		||||
    - If the JSON pointer points to an array index that does not exist, it
 | 
			
		||||
      is created an filled with a `null` value before a reference to it
 | 
			
		||||
      is returned. All indices between the current maximum and the given
 | 
			
		||||
      index are also filled with `null`.
 | 
			
		||||
    - The special value `-` is treated as a synonym for the index past the
 | 
			
		||||
      end.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  a JSON pointer
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,operatorjson_pointer}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    reference operator[](const json_pointer& ptr)
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_unchecked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
 | 
			
		||||
    No bound checking is performed. The function does not change the JSON
 | 
			
		||||
    value; no `null` values are created. In particular, the the special value
 | 
			
		||||
    `-` yields an exception.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return const reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    const_reference operator[](const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_unchecked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Returns a reference to the element at with specified JSON pointer @a ptr,
 | 
			
		||||
    with bounds checking.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,at_json_pointer}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    reference at(const json_pointer& ptr)
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_checked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief access specified element via JSON Pointer
 | 
			
		||||
 | 
			
		||||
    Returns a const reference to the element at with specified JSON pointer
 | 
			
		||||
    @a ptr, with bounds checking.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr  JSON pointer to the desired element
 | 
			
		||||
 | 
			
		||||
    @return reference to the element pointed to by @a ptr
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @throw std::out_of_range      if the JSON pointer can not be resolved
 | 
			
		||||
    @throw std::domain_error      if an array index begins with '0'
 | 
			
		||||
    @throw std::invalid_argument  if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @liveexample{The behavior is shown in the example.,at_json_pointer_const}
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    const_reference at(const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.get_checked(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief return flattened JSON value
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8815,35 +8849,119 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    /// @}
 | 
			
		||||
 | 
			
		||||
    //////////////////////////
 | 
			
		||||
    // JSON Patch functions //
 | 
			
		||||
    //////////////////////////
 | 
			
		||||
 | 
			
		||||
    /// @name JSON Patch functions
 | 
			
		||||
    /// @{
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief applies a JSON patch
 | 
			
		||||
 | 
			
		||||
    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
 | 
			
		||||
    expressing a sequence of operations to apply to a JSON) document. With
 | 
			
		||||
    this funcion, a JSON Patch is applied to the current JSON value by
 | 
			
		||||
    executing all operations from the patch.
 | 
			
		||||
 | 
			
		||||
    @param[in] patch  JSON patch document
 | 
			
		||||
    @return patched document
 | 
			
		||||
 | 
			
		||||
    @note The original JSON value is not changed; that is, the patch is
 | 
			
		||||
          applied to a copy of the value.
 | 
			
		||||
    @note The application of a patch is atomic: Either all operations succeed
 | 
			
		||||
          and the patched document is returned or an exception is thrown. In
 | 
			
		||||
          any case, the original value is not changed: the patch is applied
 | 
			
		||||
          to a copy of the value.
 | 
			
		||||
 | 
			
		||||
    @sa [RFC 6902](https://tools.ietf.org/html/rfc6902)
 | 
			
		||||
    @throw std::out_of_range if a JSON pointer inside the patch could not
 | 
			
		||||
    be resolved successfully in the current JSON value; example: `"key baz
 | 
			
		||||
    not found"`
 | 
			
		||||
    @throw invalid_argument if the JSON patch is malformed (e.g., mandatory
 | 
			
		||||
    attributes are missing); example: `"operation add must have member path"`
 | 
			
		||||
 | 
			
		||||
    @complexity Linear in the size of the JSON value and the length of the
 | 
			
		||||
    JSON patch. As usually only a fraction of the JSON value is affected by
 | 
			
		||||
    the patch, the complexity can usually be neglected.
 | 
			
		||||
 | 
			
		||||
    @liveexample{The following code shows how a JSON patch is applied to a
 | 
			
		||||
    value.,patch}
 | 
			
		||||
 | 
			
		||||
    @sa @ref diff -- create a JSON patch by comparing two JSON values
 | 
			
		||||
 | 
			
		||||
    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
 | 
			
		||||
    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    basic_json apply_patch(const basic_json& patch) const
 | 
			
		||||
    basic_json patch(const basic_json& patch) const
 | 
			
		||||
    {
 | 
			
		||||
        // make a working copy to apply the patch to
 | 
			
		||||
        basic_json result = *this;
 | 
			
		||||
 | 
			
		||||
        // the valid JSON Patch operations
 | 
			
		||||
        enum class patch_operations {add, remove, replace, move, copy, test, invalid};
 | 
			
		||||
 | 
			
		||||
        const auto get_op = [](const std::string op)
 | 
			
		||||
        {
 | 
			
		||||
            if (op == "add")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::add;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "remove")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::remove;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "replace")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::replace;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "move")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::move;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "copy")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::copy;
 | 
			
		||||
            }
 | 
			
		||||
            if (op == "test")
 | 
			
		||||
            {
 | 
			
		||||
                return patch_operations::test;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return patch_operations::invalid;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // wrapper for "add" operation; add value at ptr
 | 
			
		||||
        const auto operation_add = [&result](json_pointer & ptr, basic_json val)
 | 
			
		||||
        {
 | 
			
		||||
            // adding to the root of the target document means replacing it
 | 
			
		||||
            if (ptr.is_root())
 | 
			
		||||
            {
 | 
			
		||||
                result = val;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // make sure the top element of the pointer exists
 | 
			
		||||
                json_pointer top_pointer = ptr.top();
 | 
			
		||||
                if (top_pointer != ptr)
 | 
			
		||||
                {
 | 
			
		||||
                    basic_json& x = result.at(top_pointer);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // get reference to parent of JSON pointer ptr
 | 
			
		||||
                const auto last_path = ptr.pop_back();
 | 
			
		||||
            basic_json& parent = result.at(ptr);
 | 
			
		||||
                basic_json& parent = result[ptr];
 | 
			
		||||
 | 
			
		||||
            if (parent.is_object())
 | 
			
		||||
                switch (parent.m_type)
 | 
			
		||||
                {
 | 
			
		||||
                    case value_t::null:
 | 
			
		||||
                    case value_t::object:
 | 
			
		||||
                    {
 | 
			
		||||
                        // use operator[] to add value
 | 
			
		||||
                        parent[last_path] = val;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
            else if (parent.is_array())
 | 
			
		||||
 | 
			
		||||
                    case value_t::array:
 | 
			
		||||
                    {
 | 
			
		||||
                        if (last_path == "-")
 | 
			
		||||
                        {
 | 
			
		||||
| 
						 | 
				
			
			@ -8851,9 +8969,26 @@ class basic_json
 | 
			
		|||
                            parent.push_back(val);
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            const auto idx = std::stoi(last_path);
 | 
			
		||||
                            if (static_cast<size_type>(idx) > parent.size())
 | 
			
		||||
                            {
 | 
			
		||||
                                // avoid undefined behavior
 | 
			
		||||
                                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                // default case: insert add offset
 | 
			
		||||
                    parent.insert(parent.begin() + std::stoi(last_path), val);
 | 
			
		||||
                                parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    default:
 | 
			
		||||
                    {
 | 
			
		||||
                        throw std::domain_error("unexpected parent type " + parent.type_name());
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -8868,11 +9003,21 @@ class basic_json
 | 
			
		|||
            // remove child
 | 
			
		||||
            if (parent.is_object())
 | 
			
		||||
            {
 | 
			
		||||
                parent.erase(parent.find(last_path));
 | 
			
		||||
                // perform range check
 | 
			
		||||
                auto it = parent.find(last_path);
 | 
			
		||||
                if (it != parent.end())
 | 
			
		||||
                {
 | 
			
		||||
                    parent.erase(it);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::out_of_range("key '" + last_path + "' not found");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if (parent.is_array())
 | 
			
		||||
            {
 | 
			
		||||
                parent.erase(parent.begin() + std::stoi(last_path));
 | 
			
		||||
                // note erase performs range check
 | 
			
		||||
                parent.erase(static_cast<size_type>(std::stoi(last_path)));
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8880,7 +9025,7 @@ class basic_json
 | 
			
		|||
        if (not patch.is_array())
 | 
			
		||||
        {
 | 
			
		||||
            // a JSON patch must be an array of objects
 | 
			
		||||
            throw std::domain_error("JSON patch must be an array of objects");
 | 
			
		||||
            throw std::invalid_argument("JSON patch must be an array of objects");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // iterate and apply th eoperations
 | 
			
		||||
| 
						 | 
				
			
			@ -8900,13 +9045,13 @@ class basic_json
 | 
			
		|||
                // check if desired value is present
 | 
			
		||||
                if (it == val.m_value.object->end())
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::domain_error(error_msg + " must have member '" + member + "'");
 | 
			
		||||
                    throw std::invalid_argument(error_msg + " must have member '" + member + "'");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // check if result is of type string
 | 
			
		||||
                if (string_type and not it->second.is_string())
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::domain_error(error_msg + " must have string member '" + member + "'");
 | 
			
		||||
                    throw std::invalid_argument(error_msg + " must have string member '" + member + "'");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // no error: return value
 | 
			
		||||
| 
						 | 
				
			
			@ -8916,7 +9061,7 @@ class basic_json
 | 
			
		|||
            // type check
 | 
			
		||||
            if (not val.is_object())
 | 
			
		||||
            {
 | 
			
		||||
                throw std::domain_error("JSON patch must be an array of objects");
 | 
			
		||||
                throw std::invalid_argument("JSON patch must be an array of objects");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // collect mandatory members
 | 
			
		||||
| 
						 | 
				
			
			@ -8924,51 +9069,251 @@ class basic_json
 | 
			
		|||
            const std::string path = get_value(op, "path", true);
 | 
			
		||||
            json_pointer ptr(path);
 | 
			
		||||
 | 
			
		||||
            if (op == "add")
 | 
			
		||||
            switch (get_op(op))
 | 
			
		||||
            {
 | 
			
		||||
                case patch_operations::add:
 | 
			
		||||
                {
 | 
			
		||||
                    operation_add(ptr, get_value("add", "value", false));
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "remove")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::remove:
 | 
			
		||||
                {
 | 
			
		||||
                    operation_remove(ptr);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "replace")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::replace:
 | 
			
		||||
                {
 | 
			
		||||
                    // the "path" location must exist - use at()
 | 
			
		||||
                    result.at(ptr) = get_value("replace", "value", false);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "move")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::move:
 | 
			
		||||
                {
 | 
			
		||||
                    const std::string from_path = get_value("move", "from", true);
 | 
			
		||||
                    json_pointer from_ptr(from_path);
 | 
			
		||||
                basic_json v = result[from_ptr];
 | 
			
		||||
 | 
			
		||||
                    // the "from" location must exist - use at()
 | 
			
		||||
                    basic_json v = result.at(from_ptr);
 | 
			
		||||
 | 
			
		||||
                    // The move operation is functionally identical to a
 | 
			
		||||
                    // "remove" operation on the "from" location, followed
 | 
			
		||||
                    // immediately by an "add" operation at the target
 | 
			
		||||
                    // location with the value that was just removed.
 | 
			
		||||
                    operation_remove(from_ptr);
 | 
			
		||||
                    operation_add(ptr, v);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "copy")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::copy:
 | 
			
		||||
                {
 | 
			
		||||
                    const std::string from_path = get_value("copy", "from", true);;
 | 
			
		||||
                    const json_pointer from_ptr(from_path);
 | 
			
		||||
 | 
			
		||||
                    // the "from" location must exist - use at()
 | 
			
		||||
                    result[ptr] = result.at(from_ptr);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else if (op == "test")
 | 
			
		||||
 | 
			
		||||
                case patch_operations::test:
 | 
			
		||||
                {
 | 
			
		||||
                if (result.at(ptr) != get_value("test", "value", false))
 | 
			
		||||
                    bool success = false;
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        // check if "value" matches the one at "path"
 | 
			
		||||
                        // the "path" location must exist - use at()
 | 
			
		||||
                        success = (result.at(ptr) == get_value("test", "value", false));
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (std::out_of_range&)
 | 
			
		||||
                    {
 | 
			
		||||
                        // ignore out of range errors: success remains false
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // throw an exception if test fails
 | 
			
		||||
                    if (not success)
 | 
			
		||||
                    {
 | 
			
		||||
                        throw std::domain_error("unsuccessful: " + val.dump());
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            else
 | 
			
		||||
 | 
			
		||||
                case patch_operations::invalid:
 | 
			
		||||
                {
 | 
			
		||||
                    // op must be "add", "remove", "replace", "move", "copy", or
 | 
			
		||||
                    // "test"
 | 
			
		||||
                throw std::domain_error("operation value '" + op + "' is invalid");
 | 
			
		||||
                    throw std::invalid_argument("operation value '" + op + "' is invalid");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @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, only `remove`, `add`, and `replace` operations are
 | 
			
		||||
          generated.
 | 
			
		||||
 | 
			
		||||
    @param[in] source  JSON value to copare from
 | 
			
		||||
    @param[in] target  JSON value to copare against
 | 
			
		||||
    @param[in] path    helper value to create JSON pointers
 | 
			
		||||
 | 
			
		||||
    @return a JSON patch to convert the @a source to @a target
 | 
			
		||||
 | 
			
		||||
    @complexity Linear in the lengths of @a source and @a target.
 | 
			
		||||
 | 
			
		||||
    @liveexample{The following code shows how a JSON patch is created as a
 | 
			
		||||
    diff for two JSON values.,diff}
 | 
			
		||||
 | 
			
		||||
    @sa @ref patch -- apply a JSON patch
 | 
			
		||||
 | 
			
		||||
    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    static basic_json diff(const basic_json& source,
 | 
			
		||||
                           const basic_json& target,
 | 
			
		||||
                           std::string path = "") noexcept
 | 
			
		||||
    {
 | 
			
		||||
        // the patch
 | 
			
		||||
        basic_json result(value_t::array);
 | 
			
		||||
 | 
			
		||||
        // if the values are the same, return empty patch
 | 
			
		||||
        if (source == target)
 | 
			
		||||
        {
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (source.type() != target.type())
 | 
			
		||||
        {
 | 
			
		||||
            // different types: replace value
 | 
			
		||||
            result.push_back(
 | 
			
		||||
            {
 | 
			
		||||
                {"op", "replace"},
 | 
			
		||||
                {"path", path},
 | 
			
		||||
                {"value", target}
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            switch (source.type())
 | 
			
		||||
            {
 | 
			
		||||
                case value_t::array:
 | 
			
		||||
                {
 | 
			
		||||
                    // first pass: traverse common elements
 | 
			
		||||
                    size_t i = 0;
 | 
			
		||||
                    while (i < source.size() and i < target.size())
 | 
			
		||||
                    {
 | 
			
		||||
                        // recursive call to compare array values at index i
 | 
			
		||||
                        auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
 | 
			
		||||
                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());
 | 
			
		||||
                        ++i;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // i now reached the end of at least one array
 | 
			
		||||
                    // in a second pass, traverse the remaining elements
 | 
			
		||||
 | 
			
		||||
                    // remove my remaining elements
 | 
			
		||||
                    while (i < source.size())
 | 
			
		||||
                    {
 | 
			
		||||
                        result.push_back(object(
 | 
			
		||||
                        {
 | 
			
		||||
                            {"op", "remove"},
 | 
			
		||||
                            {"path", path + "/" + std::to_string(i)}
 | 
			
		||||
                        }));
 | 
			
		||||
                        ++i;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // add other remaining elements
 | 
			
		||||
                    while (i < target.size())
 | 
			
		||||
                    {
 | 
			
		||||
                        result.push_back(
 | 
			
		||||
                        {
 | 
			
		||||
                            {"op", "add"},
 | 
			
		||||
                            {"path", path + "/" + std::to_string(i)},
 | 
			
		||||
                            {"value", target[i]}
 | 
			
		||||
                        });
 | 
			
		||||
                        ++i;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
                    // first pass: traverse this object's elements
 | 
			
		||||
                    for (auto it = source.begin(); it != source.end(); ++it)
 | 
			
		||||
                    {
 | 
			
		||||
                        // escape the key name to be used in a JSON patch
 | 
			
		||||
                        const auto key = json_pointer::escape(it.key());
 | 
			
		||||
 | 
			
		||||
                        if (target.find(it.key()) != target.end())
 | 
			
		||||
                        {
 | 
			
		||||
                            // recursive call to compare object values at key it
 | 
			
		||||
                            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(
 | 
			
		||||
                            {
 | 
			
		||||
                                {"op", "remove"},
 | 
			
		||||
                                {"path", path + "/" + key}
 | 
			
		||||
                            }));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // second pass: traverse other object's elements
 | 
			
		||||
                    for (auto it = target.begin(); it != target.end(); ++it)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (source.find(it.key()) == source.end())
 | 
			
		||||
                        {
 | 
			
		||||
                            // found a key that is not in this -> add it
 | 
			
		||||
                            const auto key = json_pointer::escape(it.key());
 | 
			
		||||
                            result.push_back(
 | 
			
		||||
                            {
 | 
			
		||||
                                {"op", "add"},
 | 
			
		||||
                                {"path", path + "/" + key},
 | 
			
		||||
                                {"value", it.value()}
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                {
 | 
			
		||||
                    // both primitive type: replace value
 | 
			
		||||
                    result.push_back(
 | 
			
		||||
                    {
 | 
			
		||||
                        {"op", "replace"},
 | 
			
		||||
                        {"path", path},
 | 
			
		||||
                        {"value", target}
 | 
			
		||||
                    });
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8988,9 +9333,9 @@ using json = basic_json<>;
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/////////////////////////
 | 
			
		||||
// nonmember functions //
 | 
			
		||||
/////////////////////////
 | 
			
		||||
///////////////////////
 | 
			
		||||
// nonmember support //
 | 
			
		||||
///////////////////////
 | 
			
		||||
 | 
			
		||||
// specialization of std::swap, and std::hash
 | 
			
		||||
namespace std
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										716
									
								
								test/unit.cpp
									
										
									
									
									
								
							
							
						
						
									
										716
									
								
								test/unit.cpp
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue