started fixing #323
This commit is contained in:
		
							parent
							
								
									a0ef5a194c
								
							
						
					
					
						commit
						2fa8ea0f74
					
				
					 5 changed files with 101 additions and 15 deletions
				
			
		| 
						 | 
				
			
			@ -40,7 +40,7 @@ int main()
 | 
			
		|||
    // output the changed array
 | 
			
		||||
    std::cout << j["array"] << '\n';
 | 
			
		||||
 | 
			
		||||
    // "change" the arry element past the end
 | 
			
		||||
    // "change" the array element past the end
 | 
			
		||||
    j["/array/-"_json_pointer] = 55;
 | 
			
		||||
    // output the changed array
 | 
			
		||||
    std::cout << j["array"] << '\n';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								src/json.hpp
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								src/json.hpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -9436,6 +9436,12 @@ basic_json_parser_63:
 | 
			
		|||
        /*!
 | 
			
		||||
        @brief return a reference to the pointed to value
 | 
			
		||||
 | 
			
		||||
        @note This version does not throw if a value is not present, but tries
 | 
			
		||||
        to create nested values instead. For instance, calling this function
 | 
			
		||||
        with pointer `"/this/that"` on a null value is equivalent to calling
 | 
			
		||||
        `operator[]("this").operator[]("that")` on that value, effectively
 | 
			
		||||
        changing the null value to an object.
 | 
			
		||||
 | 
			
		||||
        @param[in] ptr  a JSON value
 | 
			
		||||
 | 
			
		||||
        @return reference to the JSON value pointed to by the JSON pointer
 | 
			
		||||
| 
						 | 
				
			
			@ -9450,6 +9456,12 @@ basic_json_parser_63:
 | 
			
		|||
        {
 | 
			
		||||
            for (const auto& reference_token : reference_tokens)
 | 
			
		||||
            {
 | 
			
		||||
                // error condition (cf. RFC 6901, Sect. 4)
 | 
			
		||||
                if (reference_token.size() > 1 and reference_token[0] == '0')
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::domain_error("array index must not begin with '0'");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                switch (ptr->m_type)
 | 
			
		||||
                {
 | 
			
		||||
                    case value_t::object:
 | 
			
		||||
| 
						 | 
				
			
			@ -9461,12 +9473,6 @@ basic_json_parser_63:
 | 
			
		|||
 | 
			
		||||
                    case value_t::array:
 | 
			
		||||
                    {
 | 
			
		||||
                        // error condition (cf. RFC 6901, Sect. 4)
 | 
			
		||||
                        if (reference_token.size() > 1 and reference_token[0] == '0')
 | 
			
		||||
                        {
 | 
			
		||||
                            throw std::domain_error("array index must not begin with '0'");
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (reference_token == "-")
 | 
			
		||||
                        {
 | 
			
		||||
                            // explicityly treat "-" as index beyond the end
 | 
			
		||||
| 
						 | 
				
			
			@ -9480,6 +9486,37 @@ basic_json_parser_63:
 | 
			
		|||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // null values are converted to arrays or objects
 | 
			
		||||
                    case value_t::null:
 | 
			
		||||
                    {
 | 
			
		||||
                        // check if reference token is a number
 | 
			
		||||
                        const bool nums = std::all_of(reference_token.begin(),
 | 
			
		||||
                                                      reference_token.end(),
 | 
			
		||||
                                                      [](const char x)
 | 
			
		||||
                        {
 | 
			
		||||
                            return std::isdigit(x);
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        if (nums)
 | 
			
		||||
                        {
 | 
			
		||||
                            // if reference token consists solely of numbers
 | 
			
		||||
                            // use it as array index -> create array
 | 
			
		||||
                            ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (reference_token == "-")
 | 
			
		||||
                        {
 | 
			
		||||
                            // explicityly treat "-" as index beyond the end
 | 
			
		||||
                            // which is 0 for an empty array -> create array
 | 
			
		||||
                            ptr = &ptr->operator[](0);
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            // treat reference token as key -> create object
 | 
			
		||||
                            ptr = &ptr->operator[](reference_token);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    default:
 | 
			
		||||
                    {
 | 
			
		||||
                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8733,6 +8733,12 @@ class basic_json
 | 
			
		|||
        /*!
 | 
			
		||||
        @brief return a reference to the pointed to value
 | 
			
		||||
 | 
			
		||||
        @note This version does not throw if a value is not present, but tries
 | 
			
		||||
        to create nested values instead. For instance, calling this function
 | 
			
		||||
        with pointer `"/this/that"` on a null value is equivalent to calling
 | 
			
		||||
        `operator[]("this").operator[]("that")` on that value, effectively
 | 
			
		||||
        changing the null value to an object.
 | 
			
		||||
 | 
			
		||||
        @param[in] ptr  a JSON value
 | 
			
		||||
 | 
			
		||||
        @return reference to the JSON value pointed to by the JSON pointer
 | 
			
		||||
| 
						 | 
				
			
			@ -8747,6 +8753,12 @@ class basic_json
 | 
			
		|||
        {
 | 
			
		||||
            for (const auto& reference_token : reference_tokens)
 | 
			
		||||
            {
 | 
			
		||||
                // error condition (cf. RFC 6901, Sect. 4)
 | 
			
		||||
                if (reference_token.size() > 1 and reference_token[0] == '0')
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::domain_error("array index must not begin with '0'");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                switch (ptr->m_type)
 | 
			
		||||
                {
 | 
			
		||||
                    case value_t::object:
 | 
			
		||||
| 
						 | 
				
			
			@ -8758,12 +8770,6 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
                    case value_t::array:
 | 
			
		||||
                    {
 | 
			
		||||
                        // error condition (cf. RFC 6901, Sect. 4)
 | 
			
		||||
                        if (reference_token.size() > 1 and reference_token[0] == '0')
 | 
			
		||||
                        {
 | 
			
		||||
                            throw std::domain_error("array index must not begin with '0'");
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (reference_token == "-")
 | 
			
		||||
                        {
 | 
			
		||||
                            // explicityly treat "-" as index beyond the end
 | 
			
		||||
| 
						 | 
				
			
			@ -8777,6 +8783,37 @@ class basic_json
 | 
			
		|||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // null values are converted to arrays or objects
 | 
			
		||||
                    case value_t::null:
 | 
			
		||||
                    {
 | 
			
		||||
                        // check if reference token is a number
 | 
			
		||||
                        const bool nums = std::all_of(reference_token.begin(),
 | 
			
		||||
                                                      reference_token.end(),
 | 
			
		||||
                                                      [](const char x)
 | 
			
		||||
                        {
 | 
			
		||||
                            return std::isdigit(x);
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        if (nums)
 | 
			
		||||
                        {
 | 
			
		||||
                            // if reference token consists solely of numbers
 | 
			
		||||
                            // use it as array index -> create array
 | 
			
		||||
                            ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (reference_token == "-")
 | 
			
		||||
                        {
 | 
			
		||||
                            // explicityly treat "-" as index beyond the end
 | 
			
		||||
                            // which is 0 for an empty array -> create array
 | 
			
		||||
                            ptr = &ptr->operator[](0);
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            // treat reference token as key -> create object
 | 
			
		||||
                            ptr = &ptr->operator[](reference_token);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    default:
 | 
			
		||||
                    {
 | 
			
		||||
                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,8 +109,13 @@ TEST_CASE("JSON pointers")
 | 
			
		|||
            CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]);
 | 
			
		||||
 | 
			
		||||
            // unescaped access
 | 
			
		||||
            CHECK_THROWS_AS(j[json::json_pointer("/a/b")], std::out_of_range);
 | 
			
		||||
            CHECK_THROWS_WITH(j[json::json_pointer("/a/b")], "unresolved reference token 'b'");
 | 
			
		||||
            // access to nonexisting values yield object creation
 | 
			
		||||
            CHECK_NOTHROW(j[json::json_pointer("/a/b")] = 42);
 | 
			
		||||
            CHECK(j["a"]["b"] == json(42));
 | 
			
		||||
            CHECK_NOTHROW(j[json::json_pointer("/a/c/1")] = 42);
 | 
			
		||||
            CHECK(j["a"]["c"] == json({nullptr, 42}));
 | 
			
		||||
            CHECK_NOTHROW(j[json::json_pointer("/a/d/-")] = 42);
 | 
			
		||||
            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));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -482,4 +482,11 @@ TEST_CASE("regression tests")
 | 
			
		|||
            CHECK_NOTHROW(j << f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SECTION("issue #323 - add nested object capabilities to pointers")
 | 
			
		||||
    {
 | 
			
		||||
        json j;
 | 
			
		||||
        j["/this/that"_json_pointer] = 27;
 | 
			
		||||
        CHECK(j == json({{"this", {{"that", 27}}}}));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue