✨ add contains function for JSON pointers
This commit is contained in:
		
							parent
							
								
									39011a1759
								
							
						
					
					
						commit
						258fa798f1
					
				
					 7 changed files with 338 additions and 23 deletions
				
			
		
							
								
								
									
										45
									
								
								doc/examples/contains_json_pointer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								doc/examples/contains_json_pointer.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
#include <iostream>
 | 
			
		||||
#include <nlohmann/json.hpp>
 | 
			
		||||
 | 
			
		||||
using json = nlohmann::json;
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    // create a JSON value
 | 
			
		||||
    json j =
 | 
			
		||||
    {
 | 
			
		||||
        {"number", 1}, {"string", "foo"}, {"array", {1, 2}}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    std::cout << std::boolalpha
 | 
			
		||||
              << j.contains("/number"_json_pointer) << '\n'
 | 
			
		||||
              << j.contains("/string"_json_pointer) << '\n'
 | 
			
		||||
              << j.contains("/string"_json_pointer) << '\n'
 | 
			
		||||
              << j.contains("/array"_json_pointer) << '\n'
 | 
			
		||||
              << j.contains("/array/1"_json_pointer) << '\n'
 | 
			
		||||
              << j.contains("/array/-"_json_pointer) << '\n'
 | 
			
		||||
              << j.contains("/array/4"_json_pointer) << '\n'
 | 
			
		||||
              << j.contains("/baz"_json_pointer) << std::endl;
 | 
			
		||||
 | 
			
		||||
    // out_of_range.106
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        // try to use an array index with leading '0'
 | 
			
		||||
        j.contains("/array/01"_json_pointer);
 | 
			
		||||
    }
 | 
			
		||||
    catch (json::parse_error& e)
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << e.what() << '\n';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // out_of_range.109
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        // try to use an array index that is not a number
 | 
			
		||||
        j.contains("/array/one"_json_pointer);
 | 
			
		||||
    }
 | 
			
		||||
    catch (json::parse_error& e)
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << e.what() << '\n';
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								doc/examples/contains_json_pointer.link
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								doc/examples/contains_json_pointer.link
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<a target="_blank" href="https://wandbox.org/permlink/3TJ79OzHP4vmN1Nb"><b>online</b></a>
 | 
			
		||||
							
								
								
									
										10
									
								
								doc/examples/contains_json_pointer.output
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								doc/examples/contains_json_pointer.output
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
true
 | 
			
		||||
true
 | 
			
		||||
true
 | 
			
		||||
true
 | 
			
		||||
true
 | 
			
		||||
false
 | 
			
		||||
false
 | 
			
		||||
false
 | 
			
		||||
[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'
 | 
			
		||||
[json.exception.parse_error.109] parse error: array index 'one' is not a number
 | 
			
		||||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
#include <algorithm> // all_of
 | 
			
		||||
#include <cassert> // assert
 | 
			
		||||
#include <cctype> // isdigit
 | 
			
		||||
#include <numeric> // accumulate
 | 
			
		||||
#include <string> // string
 | 
			
		||||
#include <utility> // move
 | 
			
		||||
| 
						 | 
				
			
			@ -369,7 +370,7 @@ class json_pointer
 | 
			
		|||
        // j which will be overwritten by a primitive value
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (result->m_type)
 | 
			
		||||
            switch (result->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::null:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -446,14 +447,14 @@ class json_pointer
 | 
			
		|||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            // convert null values to arrays or objects before continuing
 | 
			
		||||
            if (ptr->m_type == detail::value_t::null)
 | 
			
		||||
            if (ptr->is_null())
 | 
			
		||||
            {
 | 
			
		||||
                // check if reference token is a number
 | 
			
		||||
                const bool nums =
 | 
			
		||||
                    std::all_of(reference_token.begin(), reference_token.end(),
 | 
			
		||||
                                [](const char x)
 | 
			
		||||
                                [](const unsigned char x)
 | 
			
		||||
                {
 | 
			
		||||
                    return x >= '0' and x <= '9';
 | 
			
		||||
                    return std::isdigit(x);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // change value to array for numbers or "-" or to object otherwise
 | 
			
		||||
| 
						 | 
				
			
			@ -462,7 +463,7 @@ class json_pointer
 | 
			
		|||
                       : detail::value_t::object;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            switch (ptr->m_type)
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -521,7 +522,7 @@ class json_pointer
 | 
			
		|||
        using size_type = typename BasicJsonType::size_type;
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (ptr->m_type)
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -586,7 +587,7 @@ class json_pointer
 | 
			
		|||
        using size_type = typename BasicJsonType::size_type;
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (ptr->m_type)
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -645,7 +646,7 @@ class json_pointer
 | 
			
		|||
        using size_type = typename BasicJsonType::size_type;
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (ptr->m_type)
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -692,6 +693,77 @@ class json_pointer
 | 
			
		|||
        return *ptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @throw parse_error.106   if an array index begins with '0'
 | 
			
		||||
    @throw parse_error.109   if an array index was not a number
 | 
			
		||||
    */
 | 
			
		||||
    bool contains(const BasicJsonType* ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        using size_type = typename BasicJsonType::size_type;
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
                    if (not ptr->contains(reference_token))
 | 
			
		||||
                    {
 | 
			
		||||
                        // we did not find the key in the object
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    ptr = &ptr->operator[](reference_token);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case detail::value_t::array:
 | 
			
		||||
                {
 | 
			
		||||
                    if (JSON_UNLIKELY(reference_token == "-"))
 | 
			
		||||
                    {
 | 
			
		||||
                        // "-" always fails the range check
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // error condition (cf. RFC 6901, Sect. 4)
 | 
			
		||||
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
 | 
			
		||||
                    {
 | 
			
		||||
                        JSON_THROW(detail::parse_error::create(106, 0,
 | 
			
		||||
                                                               "array index '" + reference_token +
 | 
			
		||||
                                                               "' must not begin with '0'"));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    JSON_TRY
 | 
			
		||||
                    {
 | 
			
		||||
                        const auto idx = static_cast<size_type>(array_index(reference_token));
 | 
			
		||||
                        if (idx >= ptr->size())
 | 
			
		||||
                        {
 | 
			
		||||
                            // index out of range
 | 
			
		||||
                            return false;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        ptr = &ptr->operator[](idx);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    JSON_CATCH(std::invalid_argument&)
 | 
			
		||||
                    {
 | 
			
		||||
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                {
 | 
			
		||||
                    // we do not expect primitive values if there is still a
 | 
			
		||||
                    // reference token to process
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // no reference token left means we found a primitive value
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief split the string input to reference tokens
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -813,7 +885,7 @@ class json_pointer
 | 
			
		|||
                        const BasicJsonType& value,
 | 
			
		||||
                        BasicJsonType& result)
 | 
			
		||||
    {
 | 
			
		||||
        switch (value.m_type)
 | 
			
		||||
        switch (value.type())
 | 
			
		||||
        {
 | 
			
		||||
            case detail::value_t::array:
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4001,15 +4001,48 @@ class basic_json
 | 
			
		|||
    @liveexample{The following code shows an example for `contains()`.,contains}
 | 
			
		||||
 | 
			
		||||
    @sa @ref find(KeyT&&) -- returns an iterator to an object element
 | 
			
		||||
    @sa @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer
 | 
			
		||||
 | 
			
		||||
    @since version 3.6.0
 | 
			
		||||
    */
 | 
			
		||||
    template<typename KeyT>
 | 
			
		||||
    bool contains(KeyT&& key) const
 | 
			
		||||
    template<typename KeyT, typename std::enable_if<
 | 
			
		||||
                 not std::is_same<KeyT, json_pointer>::value, int>::type = 0>
 | 
			
		||||
    bool contains(KeyT && key) const
 | 
			
		||||
    {
 | 
			
		||||
        return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief check the existence of an element in a JSON object given a JSON pointer
 | 
			
		||||
 | 
			
		||||
    Check wehther the given JSON pointer @a ptr can be resolved in the current
 | 
			
		||||
    JSON value.
 | 
			
		||||
 | 
			
		||||
    @note This method can be executed on any JSON value type.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr JSON pointer to check its existence.
 | 
			
		||||
 | 
			
		||||
    @return true if the JSON pointer can be resolved to a stored value, false
 | 
			
		||||
    otherwise.
 | 
			
		||||
 | 
			
		||||
    @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`.
 | 
			
		||||
 | 
			
		||||
    @throw parse_error.106   if an array index begins with '0'
 | 
			
		||||
    @throw parse_error.109   if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @complexity Logarithmic in the size of the JSON object.
 | 
			
		||||
 | 
			
		||||
    @liveexample{The following code shows an example for `contains()`.,contains_json_pointer}
 | 
			
		||||
 | 
			
		||||
    @sa @ref contains(KeyT &&) const -- checks the existence of a key
 | 
			
		||||
 | 
			
		||||
    @since version 3.7.0
 | 
			
		||||
    */
 | 
			
		||||
    bool contains(const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.contains(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8445,6 +8445,7 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
 | 
			
		|||
 | 
			
		||||
#include <algorithm> // all_of
 | 
			
		||||
#include <cassert> // assert
 | 
			
		||||
#include <cctype> // isdigit
 | 
			
		||||
#include <numeric> // accumulate
 | 
			
		||||
#include <string> // string
 | 
			
		||||
#include <utility> // move
 | 
			
		||||
| 
						 | 
				
			
			@ -8815,7 +8816,7 @@ class json_pointer
 | 
			
		|||
        // j which will be overwritten by a primitive value
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (result->m_type)
 | 
			
		||||
            switch (result->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::null:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -8892,14 +8893,14 @@ class json_pointer
 | 
			
		|||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            // convert null values to arrays or objects before continuing
 | 
			
		||||
            if (ptr->m_type == detail::value_t::null)
 | 
			
		||||
            if (ptr->is_null())
 | 
			
		||||
            {
 | 
			
		||||
                // check if reference token is a number
 | 
			
		||||
                const bool nums =
 | 
			
		||||
                    std::all_of(reference_token.begin(), reference_token.end(),
 | 
			
		||||
                                [](const char x)
 | 
			
		||||
                                [](const unsigned char x)
 | 
			
		||||
                {
 | 
			
		||||
                    return x >= '0' and x <= '9';
 | 
			
		||||
                    return std::isdigit(x);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // change value to array for numbers or "-" or to object otherwise
 | 
			
		||||
| 
						 | 
				
			
			@ -8908,7 +8909,7 @@ class json_pointer
 | 
			
		|||
                       : detail::value_t::object;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            switch (ptr->m_type)
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -8967,7 +8968,7 @@ class json_pointer
 | 
			
		|||
        using size_type = typename BasicJsonType::size_type;
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (ptr->m_type)
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -9032,7 +9033,7 @@ class json_pointer
 | 
			
		|||
        using size_type = typename BasicJsonType::size_type;
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (ptr->m_type)
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -9091,7 +9092,7 @@ class json_pointer
 | 
			
		|||
        using size_type = typename BasicJsonType::size_type;
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (ptr->m_type)
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -9138,6 +9139,77 @@ class json_pointer
 | 
			
		|||
        return *ptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @throw parse_error.106   if an array index begins with '0'
 | 
			
		||||
    @throw parse_error.109   if an array index was not a number
 | 
			
		||||
    */
 | 
			
		||||
    bool contains(const BasicJsonType* ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        using size_type = typename BasicJsonType::size_type;
 | 
			
		||||
        for (const auto& reference_token : reference_tokens)
 | 
			
		||||
        {
 | 
			
		||||
            switch (ptr->type())
 | 
			
		||||
            {
 | 
			
		||||
                case detail::value_t::object:
 | 
			
		||||
                {
 | 
			
		||||
                    if (not ptr->contains(reference_token))
 | 
			
		||||
                    {
 | 
			
		||||
                        // we did not find the key in the object
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    ptr = &ptr->operator[](reference_token);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case detail::value_t::array:
 | 
			
		||||
                {
 | 
			
		||||
                    if (JSON_UNLIKELY(reference_token == "-"))
 | 
			
		||||
                    {
 | 
			
		||||
                        // "-" always fails the range check
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // error condition (cf. RFC 6901, Sect. 4)
 | 
			
		||||
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
 | 
			
		||||
                    {
 | 
			
		||||
                        JSON_THROW(detail::parse_error::create(106, 0,
 | 
			
		||||
                                                               "array index '" + reference_token +
 | 
			
		||||
                                                               "' must not begin with '0'"));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    JSON_TRY
 | 
			
		||||
                    {
 | 
			
		||||
                        const auto idx = static_cast<size_type>(array_index(reference_token));
 | 
			
		||||
                        if (idx >= ptr->size())
 | 
			
		||||
                        {
 | 
			
		||||
                            // index out of range
 | 
			
		||||
                            return false;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        ptr = &ptr->operator[](idx);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    JSON_CATCH(std::invalid_argument&)
 | 
			
		||||
                    {
 | 
			
		||||
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                {
 | 
			
		||||
                    // we do not expect primitive values if there is still a
 | 
			
		||||
                    // reference token to process
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // no reference token left means we found a primitive value
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief split the string input to reference tokens
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9259,7 +9331,7 @@ class json_pointer
 | 
			
		|||
                        const BasicJsonType& value,
 | 
			
		||||
                        BasicJsonType& result)
 | 
			
		||||
    {
 | 
			
		||||
        switch (value.m_type)
 | 
			
		||||
        switch (value.type())
 | 
			
		||||
        {
 | 
			
		||||
            case detail::value_t::array:
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -16802,15 +16874,48 @@ class basic_json
 | 
			
		|||
    @liveexample{The following code shows an example for `contains()`.,contains}
 | 
			
		||||
 | 
			
		||||
    @sa @ref find(KeyT&&) -- returns an iterator to an object element
 | 
			
		||||
    @sa @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer
 | 
			
		||||
 | 
			
		||||
    @since version 3.6.0
 | 
			
		||||
    */
 | 
			
		||||
    template<typename KeyT>
 | 
			
		||||
    bool contains(KeyT&& key) const
 | 
			
		||||
    template<typename KeyT, typename std::enable_if<
 | 
			
		||||
                 not std::is_same<KeyT, json_pointer>::value, int>::type = 0>
 | 
			
		||||
    bool contains(KeyT && key) const
 | 
			
		||||
    {
 | 
			
		||||
        return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief check the existence of an element in a JSON object given a JSON pointer
 | 
			
		||||
 | 
			
		||||
    Check wehther the given JSON pointer @a ptr can be resolved in the current
 | 
			
		||||
    JSON value.
 | 
			
		||||
 | 
			
		||||
    @note This method can be executed on any JSON value type.
 | 
			
		||||
 | 
			
		||||
    @param[in] ptr JSON pointer to check its existence.
 | 
			
		||||
 | 
			
		||||
    @return true if the JSON pointer can be resolved to a stored value, false
 | 
			
		||||
    otherwise.
 | 
			
		||||
 | 
			
		||||
    @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`.
 | 
			
		||||
 | 
			
		||||
    @throw parse_error.106   if an array index begins with '0'
 | 
			
		||||
    @throw parse_error.109   if an array index was not a number
 | 
			
		||||
 | 
			
		||||
    @complexity Logarithmic in the size of the JSON object.
 | 
			
		||||
 | 
			
		||||
    @liveexample{The following code shows an example for `contains()`.,contains_json_pointer}
 | 
			
		||||
 | 
			
		||||
    @sa @ref contains(KeyT &&) const -- checks the existence of a key
 | 
			
		||||
 | 
			
		||||
    @since version 3.7.0
 | 
			
		||||
    */
 | 
			
		||||
    bool contains(const json_pointer& ptr) const
 | 
			
		||||
    {
 | 
			
		||||
        return ptr.contains(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,12 +90,18 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            // the whole document
 | 
			
		||||
            CHECK(j[json::json_pointer()] == j);
 | 
			
		||||
            CHECK(j[json::json_pointer("")] == j);
 | 
			
		||||
            CHECK(j.contains(json::json_pointer()));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("")));
 | 
			
		||||
 | 
			
		||||
            // array access
 | 
			
		||||
            CHECK(j[json::json_pointer("/foo")] == j["foo"]);
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/foo")));
 | 
			
		||||
            CHECK(j[json::json_pointer("/foo/0")] == j["foo"][0]);
 | 
			
		||||
            CHECK(j[json::json_pointer("/foo/1")] == j["foo"][1]);
 | 
			
		||||
            CHECK(j["/foo/1"_json_pointer] == j["foo"][1]);
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/foo/0")));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/foo/1")));
 | 
			
		||||
            CHECK(not j.contains(json::json_pointer("/foo/-")));
 | 
			
		||||
 | 
			
		||||
            // checked array access
 | 
			
		||||
            CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +109,8 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
 | 
			
		||||
            // empty string access
 | 
			
		||||
            CHECK(j[json::json_pointer("/")] == j[""]);
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("")));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/")));
 | 
			
		||||
 | 
			
		||||
            // other cases
 | 
			
		||||
            CHECK(j[json::json_pointer("/ ")] == j[" "]);
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +120,14 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            CHECK(j[json::json_pointer("/i\\j")] == j["i\\j"]);
 | 
			
		||||
            CHECK(j[json::json_pointer("/k\"l")] == j["k\"l"]);
 | 
			
		||||
 | 
			
		||||
            // contains
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/ ")));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/c%d")));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/e^f")));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/g|h")));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/i\\j")));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/k\"l")));
 | 
			
		||||
 | 
			
		||||
            // checked access
 | 
			
		||||
            CHECK(j.at(json::json_pointer("/ ")) == j[" "]);
 | 
			
		||||
            CHECK(j.at(json::json_pointer("/c%d")) == j["c%d"]);
 | 
			
		||||
| 
						 | 
				
			
			@ -123,14 +139,24 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            // escaped access
 | 
			
		||||
            CHECK(j[json::json_pointer("/a~1b")] == j["a/b"]);
 | 
			
		||||
            CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]);
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/a~1b")));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/m~0n")));
 | 
			
		||||
 | 
			
		||||
            // unescaped access
 | 
			
		||||
            // access to nonexisting values yield object creation
 | 
			
		||||
            CHECK(not j.contains(json::json_pointer("/a/b")));
 | 
			
		||||
            CHECK_NOTHROW(j[json::json_pointer("/a/b")] = 42);
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/a/b")));
 | 
			
		||||
            CHECK(j["a"]["b"] == json(42));
 | 
			
		||||
 | 
			
		||||
            CHECK(not j.contains(json::json_pointer("/a/c/1")));
 | 
			
		||||
            CHECK_NOTHROW(j[json::json_pointer("/a/c/1")] = 42);
 | 
			
		||||
            CHECK(j["a"]["c"] == json({nullptr, 42}));
 | 
			
		||||
            CHECK(j.contains(json::json_pointer("/a/c/1")));
 | 
			
		||||
 | 
			
		||||
            CHECK(not j.contains(json::json_pointer("/a/d/-")));
 | 
			
		||||
            CHECK_NOTHROW(j[json::json_pointer("/a/d/-")] = 42);
 | 
			
		||||
            CHECK(not j.contains(json::json_pointer("/a/d/-")));
 | 
			
		||||
            CHECK(j["a"]["d"] == json::array({42}));
 | 
			
		||||
            // "/a/b" works for JSON {"a": {"b": 42}}
 | 
			
		||||
            CHECK(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")] == json(42));
 | 
			
		||||
| 
						 | 
				
			
			@ -143,6 +169,7 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range&);
 | 
			
		||||
            CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer),
 | 
			
		||||
                              "[json.exception.out_of_range.404] unresolved reference token 'foo'");
 | 
			
		||||
            CHECK(not j_primitive.contains(json::json_pointer("/foo")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("const access")
 | 
			
		||||
| 
						 | 
				
			
			@ -233,11 +260,16 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
 | 
			
		||||
            // the whole document
 | 
			
		||||
            CHECK(j[""_json_pointer] == j);
 | 
			
		||||
            CHECK(j.contains(""_json_pointer));
 | 
			
		||||
 | 
			
		||||
            // array access
 | 
			
		||||
            CHECK(j["/foo"_json_pointer] == j["foo"]);
 | 
			
		||||
            CHECK(j["/foo/0"_json_pointer] == j["foo"][0]);
 | 
			
		||||
            CHECK(j["/foo/1"_json_pointer] == j["foo"][1]);
 | 
			
		||||
            CHECK(j.contains("/foo"_json_pointer));
 | 
			
		||||
            CHECK(j.contains("/foo/0"_json_pointer));
 | 
			
		||||
            CHECK(j.contains("/foo/1"_json_pointer));
 | 
			
		||||
            CHECK(not j.contains("/foo/-"_json_pointer));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -278,6 +310,12 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            CHECK_THROWS_AS(j_const.at("/01"_json_pointer), json::parse_error&);
 | 
			
		||||
            CHECK_THROWS_WITH(j_const.at("/01"_json_pointer),
 | 
			
		||||
                              "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'");
 | 
			
		||||
            CHECK_THROWS_AS(j.contains("/01"_json_pointer), json::parse_error&);
 | 
			
		||||
            CHECK_THROWS_WITH(j.contains("/01"_json_pointer),
 | 
			
		||||
                              "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'");
 | 
			
		||||
            CHECK_THROWS_AS(j_const.contains("/01"_json_pointer), json::parse_error&);
 | 
			
		||||
            CHECK_THROWS_WITH(j_const.contains("/01"_json_pointer),
 | 
			
		||||
                              "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'");
 | 
			
		||||
 | 
			
		||||
            // error with incorrect numbers
 | 
			
		||||
            CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error&);
 | 
			
		||||
| 
						 | 
				
			
			@ -294,6 +332,13 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            CHECK_THROWS_WITH(j_const.at("/one"_json_pointer) == 1,
 | 
			
		||||
                              "[json.exception.parse_error.109] parse error: array index 'one' is not a number");
 | 
			
		||||
 | 
			
		||||
            CHECK_THROWS_AS(j.contains("/one"_json_pointer), json::parse_error&);
 | 
			
		||||
            CHECK_THROWS_WITH(j.contains("/one"_json_pointer),
 | 
			
		||||
                              "[json.exception.parse_error.109] parse error: array index 'one' is not a number");
 | 
			
		||||
            CHECK_THROWS_AS(j_const.contains("/one"_json_pointer), json::parse_error&);
 | 
			
		||||
            CHECK_THROWS_WITH(j_const.contains("/one"_json_pointer),
 | 
			
		||||
                              "[json.exception.parse_error.109] parse error: array index 'one' is not a number");
 | 
			
		||||
 | 
			
		||||
            CHECK_THROWS_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error&);
 | 
			
		||||
            CHECK_THROWS_WITH(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(),
 | 
			
		||||
            "[json.exception.parse_error.109] parse error: array index 'three' is not a number");
 | 
			
		||||
| 
						 | 
				
			
			@ -306,6 +351,7 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            CHECK_THROWS_AS(j_const["/-"_json_pointer], json::out_of_range&);
 | 
			
		||||
            CHECK_THROWS_WITH(j_const["/-"_json_pointer],
 | 
			
		||||
                              "[json.exception.out_of_range.402] array index '-' (3) is out of range");
 | 
			
		||||
            CHECK(not j_const.contains("/-"_json_pointer));
 | 
			
		||||
 | 
			
		||||
            // error when using "-" with at
 | 
			
		||||
            CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&);
 | 
			
		||||
| 
						 | 
				
			
			@ -314,6 +360,7 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            CHECK_THROWS_AS(j_const.at("/-"_json_pointer), json::out_of_range&);
 | 
			
		||||
            CHECK_THROWS_WITH(j_const.at("/-"_json_pointer),
 | 
			
		||||
                              "[json.exception.out_of_range.402] array index '-' (3) is out of range");
 | 
			
		||||
            CHECK(not j_const.contains("/-"_json_pointer));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("const access")
 | 
			
		||||
| 
						 | 
				
			
			@ -329,11 +376,13 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            CHECK_THROWS_AS(j.at("/3"_json_pointer), json::out_of_range&);
 | 
			
		||||
            CHECK_THROWS_WITH(j.at("/3"_json_pointer),
 | 
			
		||||
                              "[json.exception.out_of_range.401] array index 3 is out of range");
 | 
			
		||||
            CHECK(not j.contains("/3"_json_pointer));
 | 
			
		||||
 | 
			
		||||
            // assign to nonexisting index (with gap)
 | 
			
		||||
            CHECK_THROWS_AS(j.at("/5"_json_pointer), json::out_of_range&);
 | 
			
		||||
            CHECK_THROWS_WITH(j.at("/5"_json_pointer),
 | 
			
		||||
                              "[json.exception.out_of_range.401] array index 5 is out of range");
 | 
			
		||||
            CHECK(not j.contains("/5"_json_pointer));
 | 
			
		||||
 | 
			
		||||
            // assign to "-"
 | 
			
		||||
            CHECK_THROWS_AS(j["/-"_json_pointer], json::out_of_range&);
 | 
			
		||||
| 
						 | 
				
			
			@ -342,8 +391,8 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&);
 | 
			
		||||
            CHECK_THROWS_WITH(j.at("/-"_json_pointer),
 | 
			
		||||
                              "[json.exception.out_of_range.402] array index '-' (3) is out of range");
 | 
			
		||||
            CHECK(not j.contains("/-"_json_pointer));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SECTION("flatten")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue