allowing parsing from contiguous containers

This commit is contained in:
Niels 2016-08-20 20:29:33 +02:00
parent 6f3554f040
commit eef8059003
3 changed files with 144 additions and 52 deletions

View file

@ -5956,11 +5956,13 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
/*
static basic_json parse(const string_t& s, static basic_json parse(const string_t& s,
const parser_callback_t cb = nullptr) const parser_callback_t cb = nullptr)
{ {
return parser(s, cb).parse(); return parser(s, cb).parse();
} }
*/
/*! /*!
@brief deserialize from string literal @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 This function reads from an iterator range of a container with contiguous
contiguous storage of 1-byte values. Compatible container types include storage of 1-byte values. Compatible container types include
`std::vector`, `std::string`, `std::array`, `std::valarray`, and `std::vector`, `std::string`, `std::array`, `std::valarray`, and
`std::initializer_list`. Furthermore, C-style arrays can be used with `std::initializer_list`. Furthermore, C-style arrays can be used with
`std::begin()`/`std::end()`. User-defined containers can be used as long `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.** undefined behavior. **This precondition is enforced with an assertion.**
@pre Each element in the range has a size of 1 byte. Violating this @pre Each element in the range has a size of 1 byte. Violating this
precondition yields undefined behavior. **This precondition is enforced precondition yields undefined behavior. **This precondition is enforced
with an assertion.** with a static assertion.**
@pre The iterator range is nonempty. Violating this precondition yields
undefined behavior. **This precondition is enforced with an assertion.**
@warning There is no way to enforce the preconditions at compile-time. If @warning There is no way to enforce the preconditions at compile-time. If
the function is called with noncompliant iterators, the behavior the function is called with noncompliant iterators, the behavior
@ -6053,7 +6053,9 @@ class basic_json
*/ */
template <class IteratorType, typename template <class IteratorType, typename
std::enable_if< 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 , int>::type
= 0> = 0>
static basic_json parse(IteratorType first, IteratorType last, static basic_json parse(IteratorType first, IteratorType last,
@ -6069,17 +6071,40 @@ class basic_json
}).first); }).first);
// assertion to check that each element is 1 byte long // assertion to check that each element is 1 byte long
assert(std::all_of(first, last, [](decltype(*first) val) static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
{ "each element in the iterator range must have the size of 1 byte");
return sizeof(val) == 1;
}));
// assertion that the iterator range is not empty // if iterator range is empty, create a parser with an empty string
assert(std::distance(first, last) > 0); // to generate "unexpected EOF" error message
if (std::distance(first, last) <= 0)
{
return parser("").parse();
}
return parser(first, last, cb).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 @brief deserialize from stream

View file

@ -5956,11 +5956,13 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
/*
static basic_json parse(const string_t& s, static basic_json parse(const string_t& s,
const parser_callback_t cb = nullptr) const parser_callback_t cb = nullptr)
{ {
return parser(s, cb).parse(); return parser(s, cb).parse();
} }
*/
/*! /*!
@brief deserialize from string literal @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 This function reads from an iterator range of a container with contiguous
contiguous storage of 1-byte values. Compatible container types include storage of 1-byte values. Compatible container types include
`std::vector`, `std::string`, `std::array`, `std::valarray`, and `std::vector`, `std::string`, `std::array`, `std::valarray`, and
`std::initializer_list`. Furthermore, C-style arrays can be used with `std::initializer_list`. Furthermore, C-style arrays can be used with
`std::begin()`/`std::end()`. User-defined containers can be used as long `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.** undefined behavior. **This precondition is enforced with an assertion.**
@pre Each element in the range has a size of 1 byte. Violating this @pre Each element in the range has a size of 1 byte. Violating this
precondition yields undefined behavior. **This precondition is enforced precondition yields undefined behavior. **This precondition is enforced
with an assertion.** with a static assertion.**
@pre The iterator range is nonempty. Violating this precondition yields
undefined behavior. **This precondition is enforced with an assertion.**
@warning There is no way to enforce the preconditions at compile-time. If @warning There is no way to enforce the preconditions at compile-time. If
the function is called with noncompliant iterators, the behavior the function is called with noncompliant iterators, the behavior
@ -6053,7 +6053,9 @@ class basic_json
*/ */
template <class IteratorType, typename template <class IteratorType, typename
std::enable_if< 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 , int>::type
= 0> = 0>
static basic_json parse(IteratorType first, IteratorType last, static basic_json parse(IteratorType first, IteratorType last,
@ -6069,17 +6071,40 @@ class basic_json
}).first); }).first);
// assertion to check that each element is 1 byte long // assertion to check that each element is 1 byte long
assert(std::all_of(first, last, [](decltype(*first) val) static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
{ "each element in the iterator range must have the size of 1 byte");
return sizeof(val) == 1;
}));
// assertion that the iterator range is not empty // if iterator range is empty, create a parser with an empty string
assert(std::distance(first, last) > 0); // to generate "unexpected EOF" error message
if (std::distance(first, last) <= 0)
{
return parser("").parse();
}
return parser(first, last, cb).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 @brief deserialize from stream

View file

@ -82,40 +82,82 @@ TEST_CASE("deserialization")
SECTION("contiguous containers") SECTION("contiguous containers")
{ {
SECTION("from std::vector") SECTION("directly")
{ {
std::vector<uint8_t> v = {'t', 'r', 'u', 'e', '\0'}; SECTION("from std::vector")
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); {
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'} }; SECTION("from std::vector")
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); {
} std::vector<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
}
SECTION("from array") SECTION("from std::array")
{ {
uint8_t v[] = {'t', 'r', 'u', 'e', '\0'}; std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e', '\0'} };
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
} }
SECTION("from std::string") SECTION("from array")
{ {
std::string v = {'t', 'r', 'u', 'e'}; uint8_t v[] = {'t', 'r', 'u', 'e', '\0'};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
} }
SECTION("from std::initializer_list") SECTION("from std::string")
{ {
std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e', '\0'}; std::string v = {'t', 'r', 'u', 'e'};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
} }
SECTION("from std::valarray") SECTION("from std::initializer_list")
{ {
std::valarray<uint8_t> v = {'t', 'r', 'u', 'e', '\0'}; std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e', '\0'};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); 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);
}
} }
} }
} }