allowing parsing from contiguous containers
This commit is contained in:
		
							parent
							
								
									6f3554f040
								
							
						
					
					
						commit
						eef8059003
					
				
					 3 changed files with 144 additions and 52 deletions
				
			
		
							
								
								
									
										51
									
								
								src/json.hpp
									
										
									
									
									
								
							
							
						
						
									
										51
									
								
								src/json.hpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -5956,11 +5956,13 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @since version 1.0.0
 | 
			
		||||
    */
 | 
			
		||||
    /*
 | 
			
		||||
    static basic_json parse(const string_t& s,
 | 
			
		||||
                            const parser_callback_t cb = nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        return parser(s, cb).parse();
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief deserialize from string literal
 | 
			
		||||
| 
						 | 
				
			
			@ -6012,10 +6014,10 @@ class basic_json
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief deserialize from a container with contiguous storage
 | 
			
		||||
    @brief deserialize from a iterator range with contiguous storage
 | 
			
		||||
 | 
			
		||||
    This function reads from a nonempty iterator range of a container with
 | 
			
		||||
    contiguous storage of 1-byte values. Compatible container types include
 | 
			
		||||
    This function reads from an iterator range of a container with contiguous
 | 
			
		||||
    storage of 1-byte values. Compatible container types include
 | 
			
		||||
    `std::vector`, `std::string`, `std::array`, `std::valarray`, and
 | 
			
		||||
    `std::initializer_list`. Furthermore, C-style arrays can be used with
 | 
			
		||||
    `std::begin()`/`std::end()`. User-defined containers can be used as long
 | 
			
		||||
| 
						 | 
				
			
			@ -6025,9 +6027,7 @@ class basic_json
 | 
			
		|||
    undefined behavior. **This precondition is enforced with an assertion.**
 | 
			
		||||
    @pre Each element in the range has a size of 1 byte. Violating this
 | 
			
		||||
    precondition yields undefined behavior. **This precondition is enforced
 | 
			
		||||
    with an assertion.**
 | 
			
		||||
    @pre The iterator range is nonempty. Violating this precondition yields
 | 
			
		||||
    undefined behavior. **This precondition is enforced with an assertion.**
 | 
			
		||||
    with a static assertion.**
 | 
			
		||||
 | 
			
		||||
    @warning There is no way to enforce the preconditions at compile-time. If
 | 
			
		||||
             the function is called with noncompliant iterators, the behavior
 | 
			
		||||
| 
						 | 
				
			
			@ -6053,7 +6053,9 @@ class basic_json
 | 
			
		|||
    */
 | 
			
		||||
    template <class IteratorType, typename
 | 
			
		||||
              std::enable_if<
 | 
			
		||||
                  std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
 | 
			
		||||
                  std::is_base_of<
 | 
			
		||||
                      std::random_access_iterator_tag,
 | 
			
		||||
                      typename std::iterator_traits<IteratorType>::iterator_category>::value
 | 
			
		||||
                  , int>::type
 | 
			
		||||
              = 0>
 | 
			
		||||
    static basic_json parse(IteratorType first, IteratorType last,
 | 
			
		||||
| 
						 | 
				
			
			@ -6069,17 +6071,40 @@ class basic_json
 | 
			
		|||
        }).first);
 | 
			
		||||
 | 
			
		||||
        // assertion to check that each element is 1 byte long
 | 
			
		||||
        assert(std::all_of(first, last, [](decltype(*first) val)
 | 
			
		||||
        {
 | 
			
		||||
            return sizeof(val) == 1;
 | 
			
		||||
        }));
 | 
			
		||||
        static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
 | 
			
		||||
                      "each element in the iterator range must have the size of 1 byte");
 | 
			
		||||
 | 
			
		||||
        // assertion that the iterator range is not empty
 | 
			
		||||
        assert(std::distance(first, last) > 0);
 | 
			
		||||
        // if iterator range is empty, create a parser with an empty string
 | 
			
		||||
        // to generate "unexpected EOF" error message
 | 
			
		||||
        if (std::distance(first, last) <= 0)
 | 
			
		||||
        {
 | 
			
		||||
            return parser("").parse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return parser(first, last, cb).parse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<class ContiguousContainer, typename
 | 
			
		||||
             std::enable_if<
 | 
			
		||||
                 std::is_base_of<
 | 
			
		||||
                     std::random_access_iterator_tag,
 | 
			
		||||
                     typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer>()))>::iterator_category>::value
 | 
			
		||||
                 , int>::type = 0>
 | 
			
		||||
    static basic_json parse(const ContiguousContainer& c,
 | 
			
		||||
                            const parser_callback_t cb = nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        // delegate the call to the iterator-range parse overload
 | 
			
		||||
        return parse(std::begin(c), std::end(c), cb);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<class T, std::size_t N>
 | 
			
		||||
    static basic_json parse(T (&array)[N],
 | 
			
		||||
                            const parser_callback_t cb = nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        // delegate the call to the iterator-range parse overload
 | 
			
		||||
        return parse(std::begin(array), std::end(array), cb);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief deserialize from stream
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5956,11 +5956,13 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @since version 1.0.0
 | 
			
		||||
    */
 | 
			
		||||
    /*
 | 
			
		||||
    static basic_json parse(const string_t& s,
 | 
			
		||||
                            const parser_callback_t cb = nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        return parser(s, cb).parse();
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief deserialize from string literal
 | 
			
		||||
| 
						 | 
				
			
			@ -6012,10 +6014,10 @@ class basic_json
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief deserialize from a container with contiguous storage
 | 
			
		||||
    @brief deserialize from a iterator range with contiguous storage
 | 
			
		||||
 | 
			
		||||
    This function reads from a nonempty iterator range of a container with
 | 
			
		||||
    contiguous storage of 1-byte values. Compatible container types include
 | 
			
		||||
    This function reads from an iterator range of a container with contiguous
 | 
			
		||||
    storage of 1-byte values. Compatible container types include
 | 
			
		||||
    `std::vector`, `std::string`, `std::array`, `std::valarray`, and
 | 
			
		||||
    `std::initializer_list`. Furthermore, C-style arrays can be used with
 | 
			
		||||
    `std::begin()`/`std::end()`. User-defined containers can be used as long
 | 
			
		||||
| 
						 | 
				
			
			@ -6025,9 +6027,7 @@ class basic_json
 | 
			
		|||
    undefined behavior. **This precondition is enforced with an assertion.**
 | 
			
		||||
    @pre Each element in the range has a size of 1 byte. Violating this
 | 
			
		||||
    precondition yields undefined behavior. **This precondition is enforced
 | 
			
		||||
    with an assertion.**
 | 
			
		||||
    @pre The iterator range is nonempty. Violating this precondition yields
 | 
			
		||||
    undefined behavior. **This precondition is enforced with an assertion.**
 | 
			
		||||
    with a static assertion.**
 | 
			
		||||
 | 
			
		||||
    @warning There is no way to enforce the preconditions at compile-time. If
 | 
			
		||||
             the function is called with noncompliant iterators, the behavior
 | 
			
		||||
| 
						 | 
				
			
			@ -6053,7 +6053,9 @@ class basic_json
 | 
			
		|||
    */
 | 
			
		||||
    template <class IteratorType, typename
 | 
			
		||||
              std::enable_if<
 | 
			
		||||
                  std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
 | 
			
		||||
                  std::is_base_of<
 | 
			
		||||
                      std::random_access_iterator_tag,
 | 
			
		||||
                      typename std::iterator_traits<IteratorType>::iterator_category>::value
 | 
			
		||||
                  , int>::type
 | 
			
		||||
              = 0>
 | 
			
		||||
    static basic_json parse(IteratorType first, IteratorType last,
 | 
			
		||||
| 
						 | 
				
			
			@ -6069,17 +6071,40 @@ class basic_json
 | 
			
		|||
        }).first);
 | 
			
		||||
 | 
			
		||||
        // assertion to check that each element is 1 byte long
 | 
			
		||||
        assert(std::all_of(first, last, [](decltype(*first) val)
 | 
			
		||||
        {
 | 
			
		||||
            return sizeof(val) == 1;
 | 
			
		||||
        }));
 | 
			
		||||
        static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
 | 
			
		||||
                      "each element in the iterator range must have the size of 1 byte");
 | 
			
		||||
 | 
			
		||||
        // assertion that the iterator range is not empty
 | 
			
		||||
        assert(std::distance(first, last) > 0);
 | 
			
		||||
        // if iterator range is empty, create a parser with an empty string
 | 
			
		||||
        // to generate "unexpected EOF" error message
 | 
			
		||||
        if (std::distance(first, last) <= 0)
 | 
			
		||||
        {
 | 
			
		||||
            return parser("").parse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return parser(first, last, cb).parse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<class ContiguousContainer, typename
 | 
			
		||||
             std::enable_if<
 | 
			
		||||
                 std::is_base_of<
 | 
			
		||||
                     std::random_access_iterator_tag,
 | 
			
		||||
                     typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer>()))>::iterator_category>::value
 | 
			
		||||
                 , int>::type = 0>
 | 
			
		||||
    static basic_json parse(const ContiguousContainer& c,
 | 
			
		||||
                            const parser_callback_t cb = nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        // delegate the call to the iterator-range parse overload
 | 
			
		||||
        return parse(std::begin(c), std::end(c), cb);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<class T, std::size_t N>
 | 
			
		||||
    static basic_json parse(T (&array)[N],
 | 
			
		||||
                            const parser_callback_t cb = nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        // delegate the call to the iterator-range parse overload
 | 
			
		||||
        return parse(std::begin(array), std::end(array), cb);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief deserialize from stream
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,40 +82,82 @@ TEST_CASE("deserialization")
 | 
			
		|||
 | 
			
		||||
    SECTION("contiguous containers")
 | 
			
		||||
    {
 | 
			
		||||
        SECTION("from std::vector")
 | 
			
		||||
        SECTION("directly")
 | 
			
		||||
        {
 | 
			
		||||
            std::vector<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
            CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
            SECTION("from std::vector")
 | 
			
		||||
            {
 | 
			
		||||
                std::vector<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
                CHECK(json::parse(v) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SECTION("from std::array")
 | 
			
		||||
            {
 | 
			
		||||
                std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e', '\0'} };
 | 
			
		||||
                CHECK(json::parse(v) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SECTION("from array")
 | 
			
		||||
            {
 | 
			
		||||
                uint8_t v[] = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
                CHECK(json::parse(v) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SECTION("from std::string")
 | 
			
		||||
            {
 | 
			
		||||
                std::string v = {'t', 'r', 'u', 'e'};
 | 
			
		||||
                CHECK(json::parse(v) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SECTION("from std::initializer_list")
 | 
			
		||||
            {
 | 
			
		||||
                std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
                CHECK(json::parse(v) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("from std::array")
 | 
			
		||||
        SECTION("via iterator range")
 | 
			
		||||
        {
 | 
			
		||||
            std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e', '\0'} };
 | 
			
		||||
            CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
        }
 | 
			
		||||
            SECTION("from std::vector")
 | 
			
		||||
            {
 | 
			
		||||
                std::vector<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        SECTION("from array")
 | 
			
		||||
        {
 | 
			
		||||
            uint8_t v[] = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
            CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
        }
 | 
			
		||||
            SECTION("from std::array")
 | 
			
		||||
            {
 | 
			
		||||
                std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e', '\0'} };
 | 
			
		||||
                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        SECTION("from std::string")
 | 
			
		||||
        {
 | 
			
		||||
            std::string v = {'t', 'r', 'u', 'e'};
 | 
			
		||||
            CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
        }
 | 
			
		||||
            SECTION("from array")
 | 
			
		||||
            {
 | 
			
		||||
                uint8_t v[] = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        SECTION("from std::initializer_list")
 | 
			
		||||
        {
 | 
			
		||||
            std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
            CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
        }
 | 
			
		||||
            SECTION("from std::string")
 | 
			
		||||
            {
 | 
			
		||||
                std::string v = {'t', 'r', 'u', 'e'};
 | 
			
		||||
                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        SECTION("from std::valarray")
 | 
			
		||||
        {
 | 
			
		||||
            std::valarray<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
            CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
            SECTION("from std::initializer_list")
 | 
			
		||||
            {
 | 
			
		||||
                std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SECTION("from std::valarray")
 | 
			
		||||
            {
 | 
			
		||||
                std::valarray<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
 | 
			
		||||
                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SECTION("with empty range")
 | 
			
		||||
            {
 | 
			
		||||
                std::vector<uint8_t> v;
 | 
			
		||||
                CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue