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
|
@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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue